From 48ce6903cbd40331e5f829f22026d10eb88e2499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=81=D0=BB=D0=BE=D0=B2=20=D0=90=D0=BB=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20=D0=90=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Mon, 6 Feb 2023 19:51:58 +0300 Subject: [PATCH 1/7] Using C extention base class for every message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Маслов Александр Александрович --- .../cmake/custom_command.cmake | 3 +- ...idl_generator_py_generate_interfaces.cmake | 30 ++- .../resource/_idl_pkg_bases.c.em | 190 ++++++++++++++++++ .../resource/_idl_support.c.em | 44 ++-- .../resource/_import_type.c.em | 32 +++ rosidl_generator_py/resource/_msg.py.em | 46 ++++- rosidl_generator_py/resource/_msg_base.c.em | 157 +++++++++++++++ .../resource/_msg_support.c.em | 150 ++++++++------ .../rosidl_generator_py/generate_py_impl.py | 12 ++ 9 files changed, 582 insertions(+), 82 deletions(-) create mode 100644 rosidl_generator_py/resource/_idl_pkg_bases.c.em create mode 100644 rosidl_generator_py/resource/_import_type.c.em create mode 100644 rosidl_generator_py/resource/_msg_base.c.em diff --git a/rosidl_generator_py/cmake/custom_command.cmake b/rosidl_generator_py/cmake/custom_command.cmake index 203747a6..6543deea 100644 --- a/rosidl_generator_py/cmake/custom_command.cmake +++ b/rosidl_generator_py/cmake/custom_command.cmake @@ -19,7 +19,7 @@ # a different CMake subdirectory, and this command is invoked after an # add_subdirectory() call. add_custom_command( - OUTPUT ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} + OUTPUT ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} ${_generated_c_base_files} # This assumes that python_cmake_module was found, which is always the case since this is only # called from rosidl_generator_py_generate_interfaces.cmake COMMAND Python3::Interpreter ${rosidl_generator_py_BIN} @@ -39,5 +39,6 @@ else() ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} + ${_generated_c_base_files} ) endif() 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 de6a6c65..c00e047e 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -48,6 +48,7 @@ set(_output_path set(_generated_extension_files "") set(_generated_py_files "") set(_generated_c_files "") +set(_generated_c_base_files "") foreach(_typesupport_impl ${_typesupport_impls}) set(_generated_extension_${_typesupport_impl}_files "") @@ -63,6 +64,8 @@ foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) list(APPEND _generated_c_files "${_output_path}/${_parent_folder}/_${_module_name}_s.c") endforeach() +list(APPEND _generated_c_base_files + "${_output_path}/_${PROJECT_NAME}_bases.c") file(MAKE_DIRECTORY "${_output_path}") file(WRITE "${_output_path}/__init__.py" "") @@ -106,9 +109,11 @@ set(target_dependencies ${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_bases.c.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" + "${rosidl_generator_py_TEMPLATE_DIR}/_msg_base.c.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" @@ -147,7 +152,7 @@ file(WRITE "${_subdir}/CMakeLists.txt" "${_custom_command}") add_subdirectory("${_subdir}" ${rosidl_generate_interfaces_TARGET}${_target_suffix}) set_property( SOURCE - ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} + ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} ${_generated_c_base_files} PROPERTY GENERATED 1) set(_target_name_lib "${rosidl_generate_interfaces_TARGET}__rosidl_generator_py") @@ -179,6 +184,29 @@ endif() rosidl_get_typesupport_target(c_typesupport_target "${rosidl_generate_interfaces_TARGET}" "rosidl_typesupport_c") target_link_libraries(${_target_name_lib} PRIVATE ${c_typesupport_target}) + +set(_target_name_bases_lib "${rosidl_generate_interfaces_TARGET}__bases") +add_library(${_target_name_bases_lib} SHARED ${_generated_c_base_files}) +add_dependencies( + ${_target_name_bases_lib} + ${rosidl_generate_interfaces_TARGET}${_target_suffix}) +target_link_libraries(${_target_name_bases_lib} ${PythonExtra_LIBRARIES}) +target_include_directories(${_target_name_bases_lib} PRIVATE ${PythonExtra_INCLUDE_DIRS}) + +set_target_properties(${_target_name_bases_lib} 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}_bases${PythonExtra_EXTENSION_SUFFIX}" + SUFFIX "${PythonExtra_EXTENSION_EXTENSION}" +) +if(NOT rosidl_generate_interfaces_SKIP_INSTALL) + install(TARGETS ${_target_name_bases_lib} + DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}") +endif() + + foreach(_typesupport_impl ${_typesupport_impls}) find_package(${_typesupport_impl} REQUIRED) # a typesupport package might not be able to generated a target anymore diff --git a/rosidl_generator_py/resource/_idl_pkg_bases.c.em b/rosidl_generator_py/resource/_idl_pkg_bases.c.em new file mode 100644 index 00000000..5d154479 --- /dev/null +++ b/rosidl_generator_py/resource/_idl_pkg_bases.c.em @@ -0,0 +1,190 @@ +// generated from rosidl_generator_py/resource/_idl_pkg_bases.c.em +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __bases.c files +@# +@# Context: +@# - package_name (string) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@####################################################################### +@# Handle messages +@####################################################################### +@{ +from rosidl_parser.definition import Message +from rosidl_pycommon import convert_camel_case_to_lower_case_underscore + +include_directives = set() +register_functions = [] + +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ + +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=message, include_directives=include_directives, + register_functions=register_functions) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle services +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ + +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=service.request_message, include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=service.response_message, include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=service.event_message, include_directives=include_directives, + register_functions=register_functions) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle actions +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ + +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.goal, include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.result, include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.feedback, include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.send_goal_service.request_message, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.send_goal_service.response_message, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.send_goal_service.event_message, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.get_result_service.request_message, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.get_result_service.response_message, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.get_result_service.event_message, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_base.c.em', + package_name=package_name, + message=action.feedback_message, include_directives=include_directives, + register_functions=register_functions) +}@ +@[end for]@ + + +static PyModuleDef _module = { + PyModuleDef_HEAD_INIT, + .m_name = "_@(package_name)_bases", + .m_doc = "Extention module for @(package_name) messages", + .m_size = -1, +}; + + +PyMODINIT_FUNC +PyInit__@(package_name)_bases(void) +{ + PyObject * pymodule = NULL; + pymodule = PyModule_Create(&_module); + if (!pymodule) { + return NULL; + } + int8_t err; +@[for register_function in register_functions]@ + + err = @(register_function)(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 index d46c0228..3159c584 100644 --- a/rosidl_generator_py/resource/_idl_support.c.em +++ b/rosidl_generator_py/resource/_idl_support.c.em @@ -18,6 +18,8 @@ from rosidl_parser.definition import Message include_directives = set() +lazy_import_methods = set() + }@ @[for message in content.get_elements_of_type(Message)]@ @{ @@ -25,7 +27,8 @@ include_directives = set() TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=message, include_directives=include_directives) + message=message, include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @[end for]@ @ @@ -41,21 +44,24 @@ from rosidl_parser.definition import Service TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=service.request_message, include_directives=include_directives) + message=service.request_message, include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=service.response_message, include_directives=include_directives) + message=service.response_message, include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=service.event_message, include_directives=include_directives) + message=service.event_message, include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @[end for]@ @ @@ -71,21 +77,24 @@ from rosidl_parser.definition import Action TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.goal, include_directives=include_directives) + message=action.goal, include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.result, include_directives=include_directives) + message=action.result, include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.feedback, include_directives=include_directives) + message=action.feedback, include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ @@ -93,7 +102,8 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.send_goal_service.request_message, - include_directives=include_directives) + include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ @@ -101,7 +111,8 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.send_goal_service.response_message, - include_directives=include_directives) + include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ @@ -109,7 +120,8 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.send_goal_service.event_message, - include_directives=include_directives) + include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ @@ -117,7 +129,8 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.get_result_service.request_message, - include_directives=include_directives) + include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ @@ -125,7 +138,8 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.get_result_service.response_message, - include_directives=include_directives) + include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ @@ -133,13 +147,15 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.get_result_service.event_message, - include_directives=include_directives) + include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.feedback_message, include_directives=include_directives) + message=action.feedback_message, include_directives=include_directives, + lazy_import_methods=lazy_import_methods) }@ @[end for]@ diff --git a/rosidl_generator_py/resource/_import_type.c.em b/rosidl_generator_py/resource/_import_type.c.em new file mode 100644 index 00000000..e773f978 --- /dev/null +++ b/rosidl_generator_py/resource/_import_type.c.em @@ -0,0 +1,32 @@ +@{ +module_name, type_name = full_type_name.rsplit(".", maxsplit=1) +ensure_is_type = locals().get('ensure_is_type', False) +}@ +@ +static PyObject * @(func_name)() +{ + // TODO(almaslov) proper deinitialization + static PyObject * py_type = NULL; + if (py_type != NULL) { + return py_type; + } + + PyObject * module = PyImport_ImportModule("@(module_name)"); + if (!module) { + return NULL; + } + py_type = PyObject_GetAttrString(module, "@(type_name)"); + Py_DECREF(module); + if (!py_type) { + return NULL; + } +@[if ensure_is_type]@ + if (!PyType_Check(py_type)) { + PyErr_SetString(PyExc_RuntimeError, "@(type_name) is not a python type"); + return NULL; + } +@[end if]@ + + return py_type; +} + diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 61640c52..f02861f2 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -61,6 +61,8 @@ for member in message.structure.members: else: assert False member_names.append(member.name) +imports.setdefault( + f'import {package_name}._{package_name}_bases as _bases', []) # used for base type }@ @#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @ @@ -103,6 +105,30 @@ class Metaclass_@(message.structure.namespaced_type.name)(type): @[end for]@ } + def __new__(cls, *args): + new_type = super().__new__(cls, *args) + + # Ugly hack here. + # There are two purposes for __slots__ field of message class: + # 1) __slots__ field is used in ROS as a list of message members. + # Number of ROS packages rely on its value. + # 2) defining __slots__ in Python class prevents adding __dict__ + # to class instances. This behvior is desirable. + # If #1 defined in message class body, then base class member descriptors are + # overriden and no longer can be used. On the other side, any __slots__ value + # should be defined to guaratee #2. + # So we define empty list in message class body and modify it after type object + # constructed. This is neither prohibited, nor encouraged by CPython documentation. + new_type.__slots__ += [ +@[for member in message.structure.members]@ +@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +@[ continue]@ +@[ end if]@ + '_@(member.name)', +@[end for]@ + ] + return new_type + @@classmethod def __import_type_support__(cls): try: @@ -188,7 +214,7 @@ for member in message.structure.members: @[end for]@ -class @(message.structure.namespaced_type.name)(metaclass=Metaclass_@(message.structure.namespaced_type.name)): +class @(message.structure.namespaced_type.name)(_bases.@(message.structure.namespaced_type.name)Base, metaclass=Metaclass_@(message.structure.namespaced_type.name)): @[if not message.constants]@ """Message class '@(message.structure.namespaced_type.name)'.""" @[else]@ @@ -202,15 +228,9 @@ class @(message.structure.namespaced_type.name)(metaclass=Metaclass_@(message.st """ @[end if]@ - __slots__ = [ -@[for member in message.structure.members]@ -@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ -@[ continue]@ -@[ end if]@ - '_@(member.name)', -@[end for]@ - '_check_fields', - ] + # This field is modified after class creation. + # See the comment to Metaclass_@(message.structure.namespaced_type.name).__new__ + __slots__ = [] _fields_and_field_types = { @[for member in message.structure.members]@ @@ -433,7 +453,11 @@ if member.name in dict(inspect.getmembers(builtins)).keys(): @@builtins.property@(noqa_string) def @(member.name)(self):@(noqa_string) """Message field '@(member.name)'.""" +@[if isinstance(member.type, BasicType) and member.type.typename == 'octet']@ + return bytes([self._@(member.name)]) +@[else]@ return self._@(member.name) +@[end if]@ @@@(member.name).setter@(noqa_string) def @(member.name)(self, value):@(noqa_string) @@ -603,6 +627,8 @@ bound = 1.7976931348623157e+308 @[ elif isinstance(member.type, AbstractSequence)]@ self._@(member.name) = array.array('@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['type_code'])', value) @[ end if]@ +@[ elif isinstance(member.type, BasicType) and member.type.typename == 'octet']@ + self._@(member.name) = value[0] @[ else]@ self._@(member.name) = value @[ end if]@ diff --git a/rosidl_generator_py/resource/_msg_base.c.em b/rosidl_generator_py/resource/_msg_base.c.em new file mode 100644 index 00000000..bb791e09 --- /dev/null +++ b/rosidl_generator_py/resource/_msg_base.c.em @@ -0,0 +1,157 @@ +@# Included from rosidl_generator_py/resource/_idl_pkg_bases.c.em +@{ +from rosidl_generator_py.generate_py_impl import SPECIAL_NESTED_BASIC_TYPES +from rosidl_parser.definition import AbstractNestedType +from rosidl_parser.definition import AbstractSequence +from rosidl_parser.definition import AbstractString +from rosidl_parser.definition import AbstractWString +from rosidl_parser.definition import Array +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME +from rosidl_parser.definition import NamespacedType +from rosidl_pycommon import convert_camel_case_to_lower_case_underscore + + +def primitive_msg_type_to_c(type_): + from rosidl_generator_c import BASIC_IDL_TYPES_TO_C + from rosidl_parser.definition import AbstractString + from rosidl_parser.definition import AbstractWString + from rosidl_parser.definition import BasicType + if isinstance(type_, AbstractString): + return 'rosidl_runtime_c__String' + if isinstance(type_, AbstractWString): + return 'rosidl_runtime_c__U16String' + assert isinstance(type_, BasicType) + return BASIC_IDL_TYPES_TO_C[type_.typename] + + +def primitive_msg_type_to_pymember_type(type_): + BASIC_IDL_TYPES_TO_PYMEMBER_TYPE = { + 'float': 'T_DOUBLE', + 'double': 'T_DOUBLE', + 'long double': 'T_DOUBLE', + 'char': 'T_CHAR', + 'wchar': 'T_USHORT', + 'boolean': 'T_BOOL', + 'octet': 'T_UBYTE', + 'uint8': 'T_UBYTE', + 'int8': 'T_BYTE', + 'uint16': 'T_USHORT', + 'int16': 'T_SHORT', + 'uint32': 'T_UINT', + 'int32': 'T_INT', + 'uint64': 'T_ULONGLONG', + 'int64': 'T_LONGLONG', + } + return BASIC_IDL_TYPES_TO_PYMEMBER_TYPE[type_.typename] + + +header_files = [ + 'Python.h', + 'stdbool.h', + 'structmember.h' +] +}@ +@[for header_file in header_files]@ +@{ +repeated_header_file = header_file in include_directives +}@ +@[ if repeated_header_file]@ +// 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]@ + + +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ +@[for member in message.structure.members]@ +@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +@[ continue]@ +@[ end if]@ +@[ if isinstance(member.type, BasicType)]@ +@[ if member.type.typename == 'float']@ + double _@(member.name); +@[ else]@ + @(primitive_msg_type_to_c(member.type)) _@(member.name); +@[ end if]@ +@[ else isinstance(member.type, AbstractGenericString)]@ + PyObject * _@(member.name); +@[ end if]@ +@[end for]@ +} @(message.structure.namespaced_type.name)Base; + +static struct PyMemberDef @(message.structure.namespaced_type.name)Base_members[] = { +@[for member in message.structure.members]@ +@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +@[ continue]@ +@[ end if]@ + {"_@(member.name)", @ +@[ if isinstance(member.type, BasicType)]@ +@(primitive_msg_type_to_pymember_type(member.type)), @ +@[ else isinstance(member.type, AbstractGenericString)]@ +T_OBJECT, @ +@[ end if]@ +offsetof(@(message.structure.namespaced_type.name)Base, _@(member.name)), 0, NULL}, +@[end for]@ + {NULL} /* Sentinel */ +}; + + +static PyTypeObject @(message.structure.namespaced_type.name)BaseType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "@(message.structure.namespaced_type.name)Base", + .tp_doc = "Base for @(message.structure.namespaced_type.name) python class", + .tp_basicsize = sizeof(@(message.structure.namespaced_type.name)Base), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = PyType_GenericNew, + .tp_members = @(message.structure.namespaced_type.name)Base_members, +}; + + +@{ +type_name = convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name) +register_function = '_register_base_msg_type__' + '__'.join(message.structure.namespaced_type.namespaces[1:] + [type_name]) +register_functions.append(register_function) +}@ +static int8_t @(register_function)(PyObject * module) +{ + if (PyType_Ready(&@(message.structure.namespaced_type.name)BaseType) < 0) { + return 1; + } + +@[if len(message.structure.members) != 1 or member.name != EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +// PyObject * slots_tuple = Py_BuildValue(@ +@# Building string "(sss)" +"(@("s" * len(message.structure.members)))"@ +@[ for member in message.structure.members]@ +, "_@(member.name)"@ +@[ end for]@ +); +// if (!slots_tuple) { +// return 1; +// } +// int err = PyDict_SetItemString(@(message.structure.namespaced_type.name)BaseType.tp_dict, "__slots__", slots_tuple); +// Py_DECREF(slots_tuple); +// if (err) { +// return 1; +// } +@[end if]@ + + Py_INCREF(&@(message.structure.namespaced_type.name)BaseType); + if (PyModule_AddObject(module, "@(message.structure.namespaced_type.name)Base", (PyObject *) &@(message.structure.namespaced_type.name)BaseType) < 0) { + Py_DECREF(&@(message.structure.namespaced_type.name)BaseType); + return 1; + } + return 0; +} diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index 36a29454..9994573c 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -156,6 +156,42 @@ PyObject * @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_unde @[ end if]@ @[end for]@ +@# TODO(aamaslov) duplicated struct definition here +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ +@[for member in message.structure.members]@ +@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +@[ continue]@ +@[ end if]@ +@[ if isinstance(member.type, BasicType)]@ +@[ if member.type.typename == 'float']@ + double _@(member.name); +@[ else]@ + @(primitive_msg_type_to_c(member.type)) _@(member.name); +@[ end if]@ +@[ else isinstance(member.type, AbstractGenericString)]@ + PyObject * _@(member.name); +@[ end if]@ +@[end for]@ +} @(message.structure.namespaced_type.name)Base; + +@{ +for member in message.structure.members: + if isinstance(member.type, AbstractNestedType) and isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES: + if isinstance(member.type, Array): + if 'numpy.ndarray' not in lazy_import_methods: + lazy_import_methods.add('numpy.ndarray') + TEMPLATE('_import_type.c.em', full_type_name='numpy.ndarray', func_name='lazy_import_ndarray') + dtype = SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype'] + if dtype not in lazy_import_methods: + lazy_import_methods.add(dtype) + TEMPLATE('_import_type.c.em', full_type_name=dtype, func_name='lazy_import_numpy_' + member.type.value_type.typename) + elif isinstance(member.type, AbstractSequence) and 'array.array' not in lazy_import_methods: + lazy_import_methods.add('array.array') + TEMPLATE('_import_type.c.em', full_type_name='array.array', func_name='lazy_import_array') +}@ @{ module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_path.stem) class_module = '%s.%s' % ('.'.join(message.structure.namespaced_type.namespaces), module_name) @@ -518,19 +554,35 @@ nested_type = '__'.join(type_.namespaced_name()) return true; } +@{ +full_type_name = '.'.join(message.structure.namespaced_type.namespaces + [module_name, message.structure.namespaced_type.name]) +import_func_name = 'lazy_import_' + convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name) +TEMPLATE( + '_import_type.c.em', + full_type_name=full_type_name, func_name=import_func_name, ensure_is_type=True) +}@ + ROSIDL_GENERATOR_C_EXPORT PyObject * @('__'.join(message.structure.namespaced_type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name)]))__convert_to_py(void * raw_ros_message) { /* NOTE(esteve): Call constructor of @(message.structure.namespaced_type.name) */ - PyObject * _pymessage = NULL; + @(message.structure.namespaced_type.name)Base * _pymessage = NULL; { - PyObject * pymessage_module = PyImport_ImportModule("@('.'.join(message.structure.namespaced_type.namespaces)).@(module_name)"); - assert(pymessage_module); - PyObject * pymessage_class = PyObject_GetAttrString(pymessage_module, "@(message.structure.namespaced_type.name)"); - assert(pymessage_class); - Py_DECREF(pymessage_module); - _pymessage = PyObject_CallObject(pymessage_class, NULL); - Py_DECREF(pymessage_class); + PyObject * py_type = @(import_func_name)(); + if (!py_type) { + return NULL; + } + + PyTypeObject * type = (PyTypeObject *)py_type; + assert(type->tp_new); + + PyObject * empty_tuple = PyTuple_New(0); + if (!empty_tuple) { + return NULL; + } + + _pymessage = (@(message.structure.namespaced_type.name)Base *)type->tp_new(type, empty_tuple, NULL); + Py_DECREF(empty_tuple); if (!_pymessage) { return NULL; } @@ -550,15 +602,22 @@ if isinstance(type_, AbstractNestedType): type_ = type_.value_type }@ { // @(member.name) +@[ if not isinstance(member.type, BasicType)]@ PyObject * field = NULL; +@[ end if]@ @[ if isinstance(member.type, AbstractNestedType) and isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES]@ @[ if isinstance(member.type, Array)]@ - field = PyObject_GetAttrString(_pymessage, "@(member.name)"); - if (!field) { + PyObject * array_type = lazy_import_ndarray(); + if (!array_type) { return NULL; } - assert(field->ob_type != NULL); - assert(field->ob_type->tp_name != NULL); + PyObject * element_type = lazy_import_numpy_@(member.type.value_type.typename)(); + if (!element_type) { + return NULL; + } + PyObject * dims = Py_BuildValue("(i)", @(member.type.size)); + field = PyObject_CallFunctionObjArgs(array_type, dims, element_type, NULL); + Py_DECREF(dims); assert(strcmp(field->ob_type->tp_name, "numpy.ndarray") == 0); PyArrayObject * seq_field = (PyArrayObject *)field; assert(PyArray_NDIM(seq_field) == 1); @@ -567,11 +626,20 @@ if isinstance(type_, AbstractNestedType): @(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype'].replace('numpy.', 'npy_')) * dst = (@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype'].replace('numpy.', 'npy_')) *)PyArray_GETPTR1(seq_field, 0); @primitive_msg_type_to_c(member.type.value_type) * src = &(ros_message->@(member.name)[0]); memcpy(dst, src, @(member.type.size) * sizeof(@primitive_msg_type_to_c(member.type.value_type))); - Py_DECREF(field); @[ elif isinstance(member.type, AbstractSequence)]@ - field = PyObject_GetAttrString(_pymessage, "@(member.name)"); - if (!field) { - return NULL; + { + PyObject * array_type = lazy_import_array(); + if (!array_type) { + return NULL; + } + PyObject * type_code = PyUnicode_FromOrdinal('@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['type_code'])'); + assert(type_code); + + field = PyObject_CallFunctionObjArgs(array_type, type_code, NULL); + Py_DECREF(type_code); + if (!field) { + return NULL; + } } assert(field->ob_type != NULL); assert(field->ob_type->tp_name != NULL); @@ -622,7 +690,6 @@ if isinstance(type_, AbstractNestedType): } Py_DECREF(ret); } - Py_DECREF(field); @[ end if]@ @[ else]@ @[ if isinstance(type_, NamespacedType)]@ @@ -736,16 +803,6 @@ nested_type = '__'.join(type_.namespaced_name()) @[ end if]@ } assert(PySequence_Check(field)); -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'char']@ - field = Py_BuildValue("C", ros_message->@(member.name)); - if (!field) { - return NULL; - } -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'octet']@ - field = PyBytes_FromStringAndSize((const char *)&ros_message->@(member.name), 1); - if (!field) { - return NULL; - } @[ elif isinstance(member.type, AbstractString)]@ field = PyUnicode_DecodeUTF8( ros_message->@(member.name).data, @@ -763,41 +820,22 @@ nested_type = '__'.join(type_.namespaced_name()) if (!field) { return NULL; } -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'boolean']@ -@# using PyBool_FromLong allows treating the variable uniformly by calling Py_DECREF on it later - field = PyBool_FromLong(ros_message->@(member.name) ? 1 : 0); -@[ elif isinstance(member.type, BasicType) and member.type.typename in ('float', 'double')]@ - field = PyFloat_FromDouble(ros_message->@(member.name)); -@[ elif isinstance(member.type, BasicType) and member.type.typename in ( - 'int8', - 'int16', - 'int32', - )]@ - field = PyLong_FromLong(ros_message->@(member.name)); -@[ elif isinstance(member.type, BasicType) and member.type.typename in ( - 'uint8', - 'uint16', - 'uint32', - )]@ - field = PyLong_FromUnsignedLong(ros_message->@(member.name)); -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'int64']@ - field = PyLong_FromLongLong(ros_message->@(member.name)); -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'uint64']@ - field = PyLong_FromUnsignedLongLong(ros_message->@(member.name)); +@[ elif isinstance(member.type, BasicType)]@ +@# Basic types are copied directly @[ else]@ assert(false); @[ end if]@ - { - int rc = PyObject_SetAttrString(_pymessage, "@(member.name)", field); - Py_DECREF(field); - if (rc) { - return NULL; - } - } +@[ end if]@ +@ +@[ if isinstance(member.type, BasicType)]@ + _pymessage->_@(member.name) = ros_message->@(member.name); +@[ else]@ + // reference is transfered to object + _pymessage->_@(member.name) = field; @[ end if]@ } @[end for]@ // ownership of _pymessage is transferred to the caller - return _pymessage; + return (PyObject *)_pymessage; } 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 0cbaaa10..2a784c38 100644 --- a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py +++ b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py @@ -192,6 +192,18 @@ def print_warning_if_reserved_keyword(member_name, interface_type, interface_nam minimum_timestamp=latest_target_timestamp) generated_files.append(generated_file) + # expand base classes module template + template_file = os.path.join(template_dir, '_idl_pkg_bases.c.em') + generated_base_file = os.path.join(args['output_dir'], '_%s_bases.c' % package_name) + data = { + 'package_name': args['package_name'], + 'content': idl_content, + } + expand_template( + template_file, data, generated_base_file, + minimum_timestamp=latest_target_timestamp) + generated_files.append(generated_file) + return generated_files From b9289df34459774103f0b958f7d8adab95718aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=81=D0=BB=D0=BE=D0=B2=20=D0=90=D0=BB=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20=D0=90=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 7 Feb 2023 13:37:49 +0300 Subject: [PATCH 2/7] Removed commented code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Маслов Александр Александрович --- rosidl_generator_py/resource/_msg_base.c.em | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/rosidl_generator_py/resource/_msg_base.c.em b/rosidl_generator_py/resource/_msg_base.c.em index bb791e09..5f8a8268 100644 --- a/rosidl_generator_py/resource/_msg_base.c.em +++ b/rosidl_generator_py/resource/_msg_base.c.em @@ -130,24 +130,6 @@ static int8_t @(register_function)(PyObject * module) return 1; } -@[if len(message.structure.members) != 1 or member.name != EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ -// PyObject * slots_tuple = Py_BuildValue(@ -@# Building string "(sss)" -"(@("s" * len(message.structure.members)))"@ -@[ for member in message.structure.members]@ -, "_@(member.name)"@ -@[ end for]@ -); -// if (!slots_tuple) { -// return 1; -// } -// int err = PyDict_SetItemString(@(message.structure.namespaced_type.name)BaseType.tp_dict, "__slots__", slots_tuple); -// Py_DECREF(slots_tuple); -// if (err) { -// return 1; -// } -@[end if]@ - Py_INCREF(&@(message.structure.namespaced_type.name)BaseType); if (PyModule_AddObject(module, "@(message.structure.namespaced_type.name)Base", (PyObject *) &@(message.structure.namespaced_type.name)BaseType) < 0) { Py_DECREF(&@(message.structure.namespaced_type.name)BaseType); From f6d710ef168c387f5c16dc1b950004f729c6645c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=81=D0=BB=D0=BE=D0=B2=20=D0=90=D0=BB=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20=D0=90=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 8 Feb 2023 13:38:40 +0300 Subject: [PATCH 3/7] Serialization uses C struct members of message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Маслов Александр Александрович --- .../resource/_msg_support.c.em | 125 ++++-------------- 1 file changed, 23 insertions(+), 102 deletions(-) diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index 9994573c..b0e39b78 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -191,44 +191,33 @@ for member in message.structure.members: elif isinstance(member.type, AbstractSequence) and 'array.array' not in lazy_import_methods: lazy_import_methods.add('array.array') TEMPLATE('_import_type.c.em', full_type_name='array.array', func_name='lazy_import_array') -}@ -@{ + module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_path.stem) class_module = '%s.%s' % ('.'.join(message.structure.namespaced_type.namespaces), module_name) namespaced_type = message.structure.namespaced_type.name +full_type_name = '.'.join(message.structure.namespaced_type.namespaces + [module_name, message.structure.namespaced_type.name]) +import_func_name = 'lazy_import_' + convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name) +no_fields = len(message.structure.members) == 1 and message.structure.members[0].name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME +TEMPLATE( + '_import_type.c.em', + full_type_name=full_type_name, func_name=import_func_name, ensure_is_type=True) }@ ROSIDL_GENERATOR_C_EXPORT bool @('__'.join(message.structure.namespaced_type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message) { // check that the passed message is of the expected Python class { - PyObject * class_attr = PyObject_GetAttrString(_pymsg, "__class__"); - if (class_attr == NULL) { - return false; - } - PyObject * name_attr = PyObject_GetAttrString(class_attr, "__name__"); - if (name_attr == NULL) { - Py_DECREF(class_attr); - return false; - } - PyObject * module_attr = PyObject_GetAttrString(class_attr, "__module__"); - if (module_attr == NULL) { - Py_DECREF(name_attr); - Py_DECREF(class_attr); - return false; - } - - // PyUnicode_1BYTE_DATA is just a cast - assert(strncmp("@(class_module)", (char *)PyUnicode_1BYTE_DATA(module_attr), @(len(class_module))) == 0); - assert(strncmp("@(namespaced_type)", (char *)PyUnicode_1BYTE_DATA(name_attr), @(len(namespaced_type))) == 0); - - Py_DECREF(module_attr); - Py_DECREF(name_attr); - Py_DECREF(class_attr); + PyTypeObject * py_type = (PyTypeObject *)@(import_func_name)(); + assert(Py_TYPE(_pymsg) == py_type); } @(msg_typename) * ros_message = _ros_message; +@[if no_fields]@ + ros_message->@(member.name) = 0; +@[else] + @(message.structure.namespaced_type.name)Base * base_msg = (@(message.structure.namespaced_type.name)Base *)_pymsg; +@[end if]@ @[for member in message.structure.members]@ -@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +@[ if no_fields]@ ros_message->@(member.name) = 0; @[ continue]@ @[ end if]@ @@ -238,10 +227,12 @@ if isinstance(type_, AbstractNestedType): type_ = type_.value_type }@ { // @(member.name) - PyObject * field = PyObject_GetAttrString(_pymsg, "@(member.name)"); +@[ if not isinstance(member.type, BasicType)]@ + PyObject * field = base_msg->_@(member.name); if (!field) { return false; } +@[ end if]@ @[ if isinstance(type_, NamespacedType)]@ @{ nested_type = '__'.join(type_.namespaced_name()) @@ -249,20 +240,17 @@ nested_type = '__'.join(type_.namespaced_name()) @[ if isinstance(member.type, AbstractNestedType)]@ PyObject * seq_field = PySequence_Fast(field, "expected a sequence in '@(member.name)'"); if (!seq_field) { - Py_DECREF(field); return false; } @[ if isinstance(member.type, AbstractSequence)]@ 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->@(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->@(member.name).data; @@ -273,14 +261,12 @@ nested_type = '__'.join(type_.namespaced_name()) for (Py_ssize_t i = 0; i < size; ++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; } } Py_DECREF(seq_field); @[ else]@ 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; } @[ end if]@ @@ -291,21 +277,18 @@ nested_type = '__'.join(type_.namespaced_name()) Py_buffer view; int rc = PyObject_GetBuffer(field, &view, PyBUF_SIMPLE); if (rc < 0) { - Py_DECREF(field); return false; } Py_ssize_t size = view.len / sizeof(@primitive_msg_type_to_c(member.type.value_type)); if (!rosidl_runtime_c__@(member.type.value_type.typename)__Sequence__init(&(ros_message->@(member.name)), size)) { PyErr_SetString(PyExc_RuntimeError, "unable to create @(member.type.value_type.typename)__Sequence ros_message"); PyBuffer_Release(&view); - Py_DECREF(field); return false; } @primitive_msg_type_to_c(member.type.value_type) * dest = ros_message->@(member.name).data; rc = PyBuffer_ToContiguous(dest, &view, view.len, 'C'); if (rc < 0) { PyBuffer_Release(&view); - Py_DECREF(field); return false; } PyBuffer_Release(&view); @@ -325,7 +308,6 @@ nested_type = '__'.join(type_.namespaced_name()) @[ else]@ PyObject * seq_field = PySequence_Fast(field, "expected a sequence in '@(member.name)'"); if (!seq_field) { - Py_DECREF(field); return false; } @[ end if]@ @@ -333,28 +315,24 @@ nested_type = '__'.join(type_.namespaced_name()) Py_ssize_t size = PySequence_Size(field); if (-1 == size) { Py_DECREF(seq_field); - Py_DECREF(field); return false; } @[ if isinstance(member.type.value_type, AbstractString)]@ if (!rosidl_runtime_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; } @[ elif isinstance(member.type.value_type, AbstractWString)]@ if (!rosidl_runtime_c__U16String__Sequence__init(&(ros_message->@(member.name)), size)) { PyErr_SetString(PyExc_RuntimeError, "unable to create U16String__Sequence ros_message"); Py_DECREF(seq_field); - Py_DECREF(field); return false; } @[ else]@ if (!rosidl_runtime_c__@(member.type.value_type.typename)__Sequence__init(&(ros_message->@(member.name)), size)) { PyErr_SetString(PyExc_RuntimeError, "unable to create @(member.type.value_type.typename)__Sequence ros_message"); Py_DECREF(seq_field); - Py_DECREF(field); return false; } @[ end if]@ @@ -368,7 +346,6 @@ nested_type = '__'.join(type_.namespaced_name()) PyObject * item = PySequence_Fast_GET_ITEM(seq_field, i); if (!item) { Py_DECREF(seq_field); - Py_DECREF(field); return false; } @[ end if]@ @@ -392,7 +369,6 @@ nested_type = '__'.join(type_.namespaced_name()) PyObject * encoded_item = PyUnicode_AsUTF8String(item); if (!encoded_item) { Py_DECREF(seq_field); - Py_DECREF(field); return false; } rosidl_runtime_c__String__assign(&dest[i], PyBytes_AS_STRING(encoded_item)); @@ -403,7 +379,6 @@ nested_type = '__'.join(type_.namespaced_name()) PyObject * encoded_item = PyUnicode_AsUTF16String(item); if (!encoded_item) { Py_DECREF(seq_field); - Py_DECREF(field); return false; } char * buffer; @@ -412,7 +387,6 @@ nested_type = '__'.join(type_.namespaced_name()) if (rc) { Py_DECREF(encoded_item); Py_DECREF(seq_field); - Py_DECREF(field); return false; } // use offset of 2 to skip BOM mark @@ -420,7 +394,6 @@ nested_type = '__'.join(type_.namespaced_name()) Py_DECREF(encoded_item); if (!succeeded) { Py_DECREF(seq_field); - Py_DECREF(field); return false; } @[ elif isinstance(member.type.value_type, BasicType) and member.type.value_type.typename == 'boolean']@ @@ -464,18 +437,6 @@ nested_type = '__'.join(type_.namespaced_name()) } Py_DECREF(seq_field); } -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'char']@ - assert(PyUnicode_Check(field)); - PyObject * encoded_field = PyUnicode_AsUTF8String(field); - if (!encoded_field) { - Py_DECREF(field); - return false; - } - ros_message->@(member.name) = PyBytes_AS_STRING(encoded_field)[0]; - Py_DECREF(encoded_field); -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'octet']@ - assert(PyBytes_Check(field)); - ros_message->@(member.name) = PyBytes_AS_STRING(field)[0]; @[ elif isinstance(member.type, AbstractString)]@ assert(PyUnicode_Check(field)); PyObject * encoded_field = PyUnicode_AsUTF8String(field); @@ -490,7 +451,6 @@ nested_type = '__'.join(type_.namespaced_name()) // the returned string starts with a BOM mark and uses native byte order PyObject * encoded_field = PyUnicode_AsUTF16String(field); if (!encoded_field) { - Py_DECREF(field); return false; } char * buffer; @@ -498,7 +458,6 @@ nested_type = '__'.join(type_.namespaced_name()) int rc = PyBytes_AsStringAndSize(encoded_field, &buffer, &length); if (rc) { Py_DECREF(encoded_field); - Py_DECREF(field); return false; } // use offset of 2 to skip BOM mark @@ -506,62 +465,24 @@ nested_type = '__'.join(type_.namespaced_name()) bool succeeded = rosidl_runtime_c__U16String__assignn_from_char(&ros_message->@(member.name), buffer + 2, length - 2); Py_DECREF(encoded_field); if (!succeeded) { - Py_DECREF(field); return false; } } -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'boolean']@ - assert(PyBool_Check(field)); - ros_message->@(member.name) = (Py_True == field); -@[ elif isinstance(member.type, BasicType) and member.type.typename in ('float', 'double')]@ - assert(PyFloat_Check(field)); +@[ elif isinstance(member.type, BasicType)]@ @[ if member.type.typename == 'float']@ - ros_message->@(member.name) = (float)PyFloat_AS_DOUBLE(field); -@[ else]@ - ros_message->@(member.name) = PyFloat_AS_DOUBLE(field); -@[ end if]@ -@[ elif isinstance(member.type, BasicType) and member.type.typename in ( - 'int8', - 'int16', - 'int32', - )]@ - assert(PyLong_Check(field)); - ros_message->@(member.name) = (@(primitive_msg_type_to_c(member.type)))PyLong_AsLong(field); -@[ elif isinstance(member.type, BasicType) and member.type.typename in ( - 'uint8', - 'uint16', - 'uint32', - )]@ - assert(PyLong_Check(field)); -@[ if member.type.typename == 'uint32']@ - ros_message->@(member.name) = PyLong_AsUnsignedLong(field); + ros_message->@(member.name) = (float)base_msg->_@(member.name); @[ else]@ - ros_message->@(member.name) = (@(primitive_msg_type_to_c(member.type)))PyLong_AsUnsignedLong(field); + ros_message->@(member.name) = base_msg->_@(member.name); @[ end if]@ -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'int64']@ - assert(PyLong_Check(field)); - ros_message->@(member.name) = PyLong_AsLongLong(field); -@[ elif isinstance(member.type, BasicType) and member.type.typename == 'uint64']@ - assert(PyLong_Check(field)); - ros_message->@(member.name) = PyLong_AsUnsignedLongLong(field); @[ else]@ assert(false); @[ end if]@ - Py_DECREF(field); } @[end for]@ return true; } -@{ -full_type_name = '.'.join(message.structure.namespaced_type.namespaces + [module_name, message.structure.namespaced_type.name]) -import_func_name = 'lazy_import_' + convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name) -TEMPLATE( - '_import_type.c.em', - full_type_name=full_type_name, func_name=import_func_name, ensure_is_type=True) -}@ - ROSIDL_GENERATOR_C_EXPORT PyObject * @('__'.join(message.structure.namespaced_type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name)]))__convert_to_py(void * raw_ros_message) { @@ -587,13 +508,13 @@ PyObject * @('__'.join(message.structure.namespaced_type.namespaces + [convert_c return NULL; } } -@[if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +@[if no_fields]@ (void)raw_ros_message; @[else]@ @(msg_typename) * ros_message = (@(msg_typename) *)raw_ros_message; @[end if]@ @[for member in message.structure.members]@ -@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +@[ if no_fields]@ @[ continue]@ @[ end if]@ @{ From e057dfa338011e2399b74838367b4a68e08250bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=81=D0=BB=D0=BE=D0=B2=20=D0=90=D0=BB=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20=D0=90=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Thu, 9 Feb 2023 17:49:39 +0300 Subject: [PATCH 4/7] Added tp_dealloc method to fix memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Маслов Александр Александрович --- rosidl_generator_py/resource/_msg_base.c.em | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/rosidl_generator_py/resource/_msg_base.c.em b/rosidl_generator_py/resource/_msg_base.c.em index 5f8a8268..c3dd9f0c 100644 --- a/rosidl_generator_py/resource/_msg_base.c.em +++ b/rosidl_generator_py/resource/_msg_base.c.em @@ -106,6 +106,16 @@ offsetof(@(message.structure.namespaced_type.name)Base, _@(member.name)), 0, NUL {NULL} /* Sentinel */ }; +static void @(message.structure.namespaced_type.name)Base_dealloc(@(message.structure.namespaced_type.name)Base * self) +{ +@[for member in message.structure.members]@ +@[ if not isinstance(member.type, BasicType)]@ + Py_XDECREF(self->_@(member.name)); +@[ end if]@ +@[end for]@ + Py_TYPE(self)->tp_free((PyObject *)self); +} + static PyTypeObject @(message.structure.namespaced_type.name)BaseType = { PyVarObject_HEAD_INIT(NULL, 0) @@ -115,6 +125,7 @@ static PyTypeObject @(message.structure.namespaced_type.name)BaseType = { .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_new = PyType_GenericNew, + .tp_dealloc = (destructor)@(message.structure.namespaced_type.name)Base_dealloc, .tp_members = @(message.structure.namespaced_type.name)Base_members, }; From 229eb342074af7cbcc29c12874a8934992ffd39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=81=D0=BB=D0=BE=D0=B2=20=D0=90=D0=BB=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20=D0=90=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 21 Mar 2023 17:23:00 +0300 Subject: [PATCH 5/7] Use single function for module import. Proper modules deinitialization. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Маслов Александр Александрович --- ...idl_generator_py_generate_interfaces.cmake | 7 + .../example/_example_msgs_bases.c | 247 +++++++ .../example/_example_msgs_decl.h | 101 +++ .../example/_example_msgs_import.c | 116 +++ .../_example_msgs_s.ep.rosidl_typesupport_c.c | 666 ++++++++++++++++++ .../example/msg/CustomMessage.msg | 5 + rosidl_generator_py/example/msg/__init__.py | 1 + .../example/msg/_custom_message.py | 291 ++++++++ .../example/msg/_custom_message_s.c | 386 ++++++++++ .../example/srv/CustomCall.srv | 3 + rosidl_generator_py/example/srv/__init__.py | 4 + .../example/srv/_custom_call.py | 546 ++++++++++++++ .../example/srv/_custom_call_s.c | 332 +++++++++ .../resource/_idl_pkg_decl.h.em | 179 +++++ .../resource/_idl_pkg_import.c.em | 204 ++++++ .../_idl_pkg_typesupport_entry_point.c.em | 51 +- .../resource/_idl_support.c.em | 43 +- .../resource/_import_type.c.em | 32 - rosidl_generator_py/resource/_msg_base.c.em | 23 +- rosidl_generator_py/resource/_msg_decl.h.em | 116 +++ .../resource/_msg_support.c.em | 59 +- .../rosidl_generator_py/generate_py_impl.py | 27 +- 22 files changed, 3280 insertions(+), 159 deletions(-) create mode 100644 rosidl_generator_py/example/_example_msgs_bases.c create mode 100644 rosidl_generator_py/example/_example_msgs_decl.h create mode 100644 rosidl_generator_py/example/_example_msgs_import.c create mode 100644 rosidl_generator_py/example/_example_msgs_s.ep.rosidl_typesupport_c.c create mode 100644 rosidl_generator_py/example/msg/CustomMessage.msg create mode 100644 rosidl_generator_py/example/msg/__init__.py create mode 100644 rosidl_generator_py/example/msg/_custom_message.py create mode 100644 rosidl_generator_py/example/msg/_custom_message_s.c create mode 100644 rosidl_generator_py/example/srv/CustomCall.srv create mode 100644 rosidl_generator_py/example/srv/__init__.py create mode 100644 rosidl_generator_py/example/srv/_custom_call.py create mode 100644 rosidl_generator_py/example/srv/_custom_call_s.c create mode 100644 rosidl_generator_py/resource/_idl_pkg_decl.h.em create mode 100644 rosidl_generator_py/resource/_idl_pkg_import.c.em delete mode 100644 rosidl_generator_py/resource/_import_type.c.em create mode 100644 rosidl_generator_py/resource/_msg_decl.h.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 c00e047e..4912f16b 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -66,6 +66,11 @@ foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) endforeach() list(APPEND _generated_c_base_files "${_output_path}/_${PROJECT_NAME}_bases.c") +if(NOT _generated_c_files STREQUAL "") + list(APPEND _generated_c_files + "${_output_path}/_${PROJECT_NAME}_decl.h" + "${_output_path}/_${PROJECT_NAME}_import.c") +endif() file(MAKE_DIRECTORY "${_output_path}") file(WRITE "${_output_path}/__init__.py" "") @@ -110,6 +115,8 @@ set(target_dependencies "${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_bases.c.em" + "${rosidl_generator_py_TEMPLATE_DIR}/_idl_pkg_decl.h.em" + "${rosidl_generator_py_TEMPLATE_DIR}/_idl_pkg_import.c.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/example/_example_msgs_bases.c b/rosidl_generator_py/example/_example_msgs_bases.c new file mode 100644 index 00000000..76ba4a8e --- /dev/null +++ b/rosidl_generator_py/example/_example_msgs_bases.c @@ -0,0 +1,247 @@ +// generated from rosidl_generator_py/resource/_idl_pkg_bases.c.em +// generated code does not contain a copyright notice +#include +#include +#include +#include "./_example_msgs_decl.h" + + +static struct PyMemberDef CustomMessageBase_members[] = { + {"_x", T_USHORT, offsetof(CustomMessageBase, _x), 0, NULL}, + {"_ts", T_OBJECT, offsetof(CustomMessageBase, _ts), 0, NULL}, + {"_fixed_seq", T_OBJECT, offsetof(CustomMessageBase, _fixed_seq), 0, NULL}, + {"_limited_seq", T_OBJECT, offsetof(CustomMessageBase, _limited_seq), 0, NULL}, + {"_unlimited_seq", T_OBJECT, offsetof(CustomMessageBase, _unlimited_seq), 0, NULL}, + {NULL} /* Sentinel */ +}; + +static void CustomMessageBase_dealloc(CustomMessageBase * self) +{ + Py_XDECREF(self->_ts); + Py_XDECREF(self->_fixed_seq); + Py_XDECREF(self->_limited_seq); + Py_XDECREF(self->_unlimited_seq); + Py_TYPE(self)->tp_free((PyObject *)self); +} + + +static PyTypeObject CustomMessageBaseType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "CustomMessageBase", + .tp_doc = "Base for CustomMessage python class", + .tp_basicsize = sizeof(CustomMessageBase), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = PyType_GenericNew, + .tp_dealloc = (destructor)CustomMessageBase_dealloc, + .tp_members = CustomMessageBase_members, +}; + + +static int8_t _register_base_msg_type__msg__custom_message(PyObject * module) +{ + if (PyType_Ready(&CustomMessageBaseType) < 0) { + return 1; + } + + Py_INCREF(&CustomMessageBaseType); + if (PyModule_AddObject(module, "CustomMessageBase", (PyObject *) &CustomMessageBaseType) < 0) { + Py_DECREF(&CustomMessageBaseType); + return 1; + } + return 0; +} +// already included above +// #include +// already included above +// #include +// already included above +// #include +// already included above +// #include "./_example_msgs_decl.h" + + +static struct PyMemberDef CustomCall_RequestBase_members[] = { + {"_my_param", T_INT, offsetof(CustomCall_RequestBase, _my_param), 0, NULL}, + {NULL} /* Sentinel */ +}; + +static void CustomCall_RequestBase_dealloc(CustomCall_RequestBase * self) +{ + Py_TYPE(self)->tp_free((PyObject *)self); +} + + +static PyTypeObject CustomCall_RequestBaseType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "CustomCall_RequestBase", + .tp_doc = "Base for CustomCall_Request python class", + .tp_basicsize = sizeof(CustomCall_RequestBase), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = PyType_GenericNew, + .tp_dealloc = (destructor)CustomCall_RequestBase_dealloc, + .tp_members = CustomCall_RequestBase_members, +}; + + +static int8_t _register_base_msg_type__srv__custom_call__request(PyObject * module) +{ + if (PyType_Ready(&CustomCall_RequestBaseType) < 0) { + return 1; + } + + Py_INCREF(&CustomCall_RequestBaseType); + if (PyModule_AddObject(module, "CustomCall_RequestBase", (PyObject *) &CustomCall_RequestBaseType) < 0) { + Py_DECREF(&CustomCall_RequestBaseType); + return 1; + } + return 0; +} + +// already included above +// #include +// already included above +// #include +// already included above +// #include +// already included above +// #include "./_example_msgs_decl.h" + + +static struct PyMemberDef CustomCall_ResponseBase_members[] = { + {"_my_result", T_INT, offsetof(CustomCall_ResponseBase, _my_result), 0, NULL}, + {NULL} /* Sentinel */ +}; + +static void CustomCall_ResponseBase_dealloc(CustomCall_ResponseBase * self) +{ + Py_TYPE(self)->tp_free((PyObject *)self); +} + + +static PyTypeObject CustomCall_ResponseBaseType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "CustomCall_ResponseBase", + .tp_doc = "Base for CustomCall_Response python class", + .tp_basicsize = sizeof(CustomCall_ResponseBase), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = PyType_GenericNew, + .tp_dealloc = (destructor)CustomCall_ResponseBase_dealloc, + .tp_members = CustomCall_ResponseBase_members, +}; + + +static int8_t _register_base_msg_type__srv__custom_call__response(PyObject * module) +{ + if (PyType_Ready(&CustomCall_ResponseBaseType) < 0) { + return 1; + } + + Py_INCREF(&CustomCall_ResponseBaseType); + if (PyModule_AddObject(module, "CustomCall_ResponseBase", (PyObject *) &CustomCall_ResponseBaseType) < 0) { + Py_DECREF(&CustomCall_ResponseBaseType); + return 1; + } + return 0; +} + +// already included above +// #include +// already included above +// #include +// already included above +// #include +// already included above +// #include "./_example_msgs_decl.h" + + +static struct PyMemberDef CustomCall_EventBase_members[] = { + {"_info", T_OBJECT, offsetof(CustomCall_EventBase, _info), 0, NULL}, + {"_request", T_OBJECT, offsetof(CustomCall_EventBase, _request), 0, NULL}, + {"_response", T_OBJECT, offsetof(CustomCall_EventBase, _response), 0, NULL}, + {NULL} /* Sentinel */ +}; + +static void CustomCall_EventBase_dealloc(CustomCall_EventBase * self) +{ + Py_XDECREF(self->_info); + Py_XDECREF(self->_request); + Py_XDECREF(self->_response); + Py_TYPE(self)->tp_free((PyObject *)self); +} + + +static PyTypeObject CustomCall_EventBaseType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "CustomCall_EventBase", + .tp_doc = "Base for CustomCall_Event python class", + .tp_basicsize = sizeof(CustomCall_EventBase), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = PyType_GenericNew, + .tp_dealloc = (destructor)CustomCall_EventBase_dealloc, + .tp_members = CustomCall_EventBase_members, +}; + + +static int8_t _register_base_msg_type__srv__custom_call__event(PyObject * module) +{ + if (PyType_Ready(&CustomCall_EventBaseType) < 0) { + return 1; + } + + Py_INCREF(&CustomCall_EventBaseType); + if (PyModule_AddObject(module, "CustomCall_EventBase", (PyObject *) &CustomCall_EventBaseType) < 0) { + Py_DECREF(&CustomCall_EventBaseType); + return 1; + } + return 0; +} + + +static PyModuleDef _module = { + PyModuleDef_HEAD_INIT, + .m_name = "_example_msgs_bases", + .m_doc = "Extention module for example_msgs messages", + .m_size = -1, +}; + + +PyMODINIT_FUNC +PyInit__example_msgs_bases(void) +{ + PyObject * pymodule = NULL; + pymodule = PyModule_Create(&_module); + if (!pymodule) { + return NULL; + } + int8_t err; + + err = _register_base_msg_type__msg__custom_message(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_base_msg_type__srv__custom_call__request(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_base_msg_type__srv__custom_call__response(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_base_msg_type__srv__custom_call__event(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + return pymodule; +} diff --git a/rosidl_generator_py/example/_example_msgs_decl.h b/rosidl_generator_py/example/_example_msgs_decl.h new file mode 100644 index 00000000..1c606479 --- /dev/null +++ b/rosidl_generator_py/example/_example_msgs_decl.h @@ -0,0 +1,101 @@ +// generated from rosidl_generator_py/resource/_idl_pkg_decl.c.em +// generated code does not contain a copyright notice +#pragma once +#include +#include +#include + + +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + uint16_t _x; + PyObject * _ts; + PyObject * _fixed_seq; + PyObject * _limited_seq; + PyObject * _unlimited_seq; +} CustomMessageBase; + +// Import support constants for CustomMessageBase type +#define NUMPY__NDARRAY__IMPORT_INDEX 0 +#define NUMPY__INT16__IMPORT_INDEX 1 +#define ARRAY__ARRAY__IMPORT_INDEX 2 +#define EXAMPLE_MSGS__MSG__CUSTOM_MESSAGE__IMPORT_INDEX 3 + +// already included above +// #include +// already included above +// #include +// already included above +// #include + + +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + int32_t _my_param; +} CustomCall_RequestBase; + +// Import support constants for CustomCall_RequestBase type +#define EXAMPLE_MSGS__SRV__CUSTOM_CALL__REQUEST__IMPORT_INDEX 4 + + +// already included above +// #include +// already included above +// #include +// already included above +// #include + + +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + int32_t _my_result; +} CustomCall_ResponseBase; + +// Import support constants for CustomCall_ResponseBase type +#define EXAMPLE_MSGS__SRV__CUSTOM_CALL__RESPONSE__IMPORT_INDEX 5 + + +// already included above +// #include +// already included above +// #include +// already included above +// #include + + +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + PyObject * _info; + PyObject * _request; + PyObject * _response; +} CustomCall_EventBase; + +// Import support constants for CustomCall_EventBase type +#define EXAMPLE_MSGS__SRV__CUSTOM_CALL__EVENT__IMPORT_INDEX 6 + + +#define MAX__IMPORT_INDEX 7 + +typedef struct lazy_import_state +{ + PyObject * cached_imports[MAX__IMPORT_INDEX]; +} lazy_import_state; + +int example_msgs__lazy_import_initialize(lazy_import_state * state); +int example_msgs__lazy_import_finalize(lazy_import_state * state); +PyObject * example_msgs__lazy_import(lazy_import_state * state, size_t index); + +// Since lazy cache global state is shared between multiple typesupport implementations, +// its lifetime should be managed carefully. Extention module can call `__lazy_import` +// function only between `__lazy_import_acquire` and `__lazy_import_release` calls. +// This functions should be removed when cache state becomes module specific. +int example_msgs__lazy_import_acquire(); +int example_msgs__lazy_import_release(); diff --git a/rosidl_generator_py/example/_example_msgs_import.c b/rosidl_generator_py/example/_example_msgs_import.c new file mode 100644 index 00000000..cc00290e --- /dev/null +++ b/rosidl_generator_py/example/_example_msgs_import.c @@ -0,0 +1,116 @@ +// generated from rosidl_generator_py/resource/_idl_pkg_import.c.em +// generated code does not contain a copyright notice +#include +#include +#include "./_example_msgs_decl.h" + + +typedef struct +{ + const char * module_name; + const char * object_name; + bool ensure_is_type; +} lazy_import_info; + + +static lazy_import_info import_infos[MAX__IMPORT_INDEX] = { + // numpy.ndarray + [NUMPY__NDARRAY__IMPORT_INDEX] = {"numpy", "ndarray", false}, + // numpy.int16 + [NUMPY__INT16__IMPORT_INDEX] = {"numpy", "int16", false}, + // array.array + [ARRAY__ARRAY__IMPORT_INDEX] = {"array", "array", false}, + // example_msgs.msg.CustomMessage + [EXAMPLE_MSGS__MSG__CUSTOM_MESSAGE__IMPORT_INDEX] = {"example_msgs.msg._custom_message", "CustomMessage", true}, + // example_msgs.srv.CustomCall_Request + [EXAMPLE_MSGS__SRV__CUSTOM_CALL__REQUEST__IMPORT_INDEX] = {"example_msgs.srv._custom_call", "CustomCall_Request", true}, + // example_msgs.srv.CustomCall_Response + [EXAMPLE_MSGS__SRV__CUSTOM_CALL__RESPONSE__IMPORT_INDEX] = {"example_msgs.srv._custom_call", "CustomCall_Response", true}, + // example_msgs.srv.CustomCall_Event + [EXAMPLE_MSGS__SRV__CUSTOM_CALL__EVENT__IMPORT_INDEX] = {"example_msgs.srv._custom_call", "CustomCall_Event", true}, +}; + +int example_msgs__lazy_import_initialize(lazy_import_state * state) +{ + assert(state != NULL); + for (size_t i = 0; i < MAX__IMPORT_INDEX; ++i) { + state->cached_imports[i] = NULL; + } + return 0; +} + +int example_msgs__lazy_import_finalize(lazy_import_state * state) +{ + assert(state != NULL); + for (size_t i = 0; i < MAX__IMPORT_INDEX; ++i) { + Py_CLEAR(state->cached_imports[i]); + } + return 0; +} + + +static PyObject * state_storage = NULL; + +PyObject * example_msgs__lazy_import(lazy_import_state * state, size_t index) +{ + if (state == NULL) { + if (state_storage == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Internal error. Module not initilized properly"); + return NULL; + } + state = (lazy_import_state *)PyCapsule_GetPointer(state_storage, NULL); + if (state == NULL) { + return NULL; + } + } + + assert(index < MAX__IMPORT_INDEX); + PyObject * py_type = state->cached_imports[index]; + if (py_type != NULL) { + return py_type; + } + + const lazy_import_info * info = &import_infos[index]; + PyObject * module = PyImport_ImportModule(info->module_name); + if (!module) { + return NULL; + } + py_type = PyObject_GetAttrString(module, info->object_name); + Py_DECREF(module); + if (!py_type) { + return NULL; + } + if (info->ensure_is_type && !PyType_Check(py_type)) { + PyErr_SetString(PyExc_RuntimeError, "Imported object is not a python type"); + return NULL; + } + + state->cached_imports[index] = py_type; + return py_type; +} + +static void clear_storage(PyObject * capsule) +{ + (void)capsule; + state_storage = NULL; +} + +int example_msgs__lazy_import_acquire() +{ + if (state_storage == NULL) { + lazy_import_state * state = PyMem_Malloc(sizeof(lazy_import_state)); + if (example_msgs__lazy_import_initialize(state) != 0) { + return 1; + } + state_storage = PyCapsule_New(state, NULL, clear_storage); + } else { + Py_INCREF(state_storage); + } + return 0; +} + +int example_msgs__lazy_import_release() +{ + Py_DECREF(state_storage); + return 0; +} diff --git a/rosidl_generator_py/example/_example_msgs_s.ep.rosidl_typesupport_c.c b/rosidl_generator_py/example/_example_msgs_s.ep.rosidl_typesupport_c.c new file mode 100644 index 00000000..910ce57a --- /dev/null +++ b/rosidl_generator_py/example/_example_msgs_s.ep.rosidl_typesupport_c.c @@ -0,0 +1,666 @@ +// generated from rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em +// generated code does not contain a copyright notice +#include + +#include +#include +#include "rosidl_runtime_c/visibility_control.h" +#include "rosidl_runtime_c/message_type_support_struct.h" +#include "rosidl_runtime_c/service_type_support_struct.h" +#include "rosidl_runtime_c/action_type_support_struct.h" +#include "example_msgs/msg/detail/custom_message__type_support.h" +#include "example_msgs/msg/detail/custom_message__struct.h" +#include "example_msgs/msg/detail/custom_message__functions.h" + +static void * example_msgs__msg__custom_message__create_ros_message(void) +{ + return example_msgs__msg__CustomMessage__create(); +} + +static void example_msgs__msg__custom_message__destroy_ros_message(void * raw_ros_message) +{ + example_msgs__msg__CustomMessage * ros_message = (example_msgs__msg__CustomMessage *)raw_ros_message; + example_msgs__msg__CustomMessage__destroy(ros_message); +} + +ROSIDL_GENERATOR_C_IMPORT +bool example_msgs__msg__custom_message__convert_from_py(PyObject * _pymsg, void * ros_message); +ROSIDL_GENERATOR_C_IMPORT +PyObject * example_msgs__msg__custom_message__convert_to_py(void * raw_ros_message); + + +ROSIDL_GENERATOR_C_IMPORT +const rosidl_message_type_support_t * +ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, msg, CustomMessage); + +int8_t +_register_msg_type__msg__custom_message(PyObject * pymodule) +{ + int8_t err; + + PyObject * pyobject_create_ros_message = NULL; + pyobject_create_ros_message = PyCapsule_New( + (void *)&example_msgs__msg__custom_message__create_ros_message, + NULL, NULL); + if (!pyobject_create_ros_message) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "create_ros_message_msg__msg__custom_message", + pyobject_create_ros_message); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_create_ros_message); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_destroy_ros_message = NULL; + pyobject_destroy_ros_message = PyCapsule_New( + (void *)&example_msgs__msg__custom_message__destroy_ros_message, + NULL, NULL); + if (!pyobject_destroy_ros_message) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "destroy_ros_message_msg__msg__custom_message", + pyobject_destroy_ros_message); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_destroy_ros_message); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_convert_from_py = NULL; + pyobject_convert_from_py = PyCapsule_New( + (void *)&example_msgs__msg__custom_message__convert_from_py, + NULL, NULL); + if (!pyobject_convert_from_py) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "convert_from_py_msg__msg__custom_message", + pyobject_convert_from_py); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_convert_from_py); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_convert_to_py = NULL; + pyobject_convert_to_py = PyCapsule_New( + (void *)&example_msgs__msg__custom_message__convert_to_py, + NULL, NULL); + if (!pyobject_convert_to_py) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "convert_to_py_msg__msg__custom_message", + pyobject_convert_to_py); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_convert_to_py); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_type_support = NULL; + pyobject_type_support = PyCapsule_New( + (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, msg, CustomMessage), + NULL, NULL); + if (!pyobject_type_support) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "type_support_msg__msg__custom_message", + pyobject_type_support); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_type_support); + // previously added objects will be removed when the module is destroyed + return err; + } + return 0; +} + +// already included above +// #include +// already included above +// #include +// already included above +// #include "rosidl_runtime_c/visibility_control.h" +// already included above +// #include "rosidl_runtime_c/message_type_support_struct.h" +// already included above +// #include "rosidl_runtime_c/service_type_support_struct.h" +// already included above +// #include "rosidl_runtime_c/action_type_support_struct.h" +#include "example_msgs/srv/detail/custom_call__type_support.h" +#include "example_msgs/srv/detail/custom_call__struct.h" +#include "example_msgs/srv/detail/custom_call__functions.h" + +static void * example_msgs__srv__custom_call__request__create_ros_message(void) +{ + return example_msgs__srv__CustomCall_Request__create(); +} + +static void example_msgs__srv__custom_call__request__destroy_ros_message(void * raw_ros_message) +{ + example_msgs__srv__CustomCall_Request * ros_message = (example_msgs__srv__CustomCall_Request *)raw_ros_message; + example_msgs__srv__CustomCall_Request__destroy(ros_message); +} + +ROSIDL_GENERATOR_C_IMPORT +bool example_msgs__srv__custom_call__request__convert_from_py(PyObject * _pymsg, void * ros_message); +ROSIDL_GENERATOR_C_IMPORT +PyObject * example_msgs__srv__custom_call__request__convert_to_py(void * raw_ros_message); + + +ROSIDL_GENERATOR_C_IMPORT +const rosidl_message_type_support_t * +ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Request); + +int8_t +_register_msg_type__srv__custom_call__request(PyObject * pymodule) +{ + int8_t err; + + PyObject * pyobject_create_ros_message = NULL; + pyobject_create_ros_message = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__request__create_ros_message, + NULL, NULL); + if (!pyobject_create_ros_message) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "create_ros_message_msg__srv__custom_call__request", + pyobject_create_ros_message); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_create_ros_message); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_destroy_ros_message = NULL; + pyobject_destroy_ros_message = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__request__destroy_ros_message, + NULL, NULL); + if (!pyobject_destroy_ros_message) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "destroy_ros_message_msg__srv__custom_call__request", + pyobject_destroy_ros_message); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_destroy_ros_message); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_convert_from_py = NULL; + pyobject_convert_from_py = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__request__convert_from_py, + NULL, NULL); + if (!pyobject_convert_from_py) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "convert_from_py_msg__srv__custom_call__request", + pyobject_convert_from_py); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_convert_from_py); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_convert_to_py = NULL; + pyobject_convert_to_py = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__request__convert_to_py, + NULL, NULL); + if (!pyobject_convert_to_py) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "convert_to_py_msg__srv__custom_call__request", + pyobject_convert_to_py); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_convert_to_py); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_type_support = NULL; + pyobject_type_support = PyCapsule_New( + (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Request), + NULL, NULL); + if (!pyobject_type_support) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "type_support_msg__srv__custom_call__request", + pyobject_type_support); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_type_support); + // previously added objects will be removed when the module is destroyed + return err; + } + return 0; +} + +// already included above +// #include +// already included above +// #include +// already included above +// #include "rosidl_runtime_c/visibility_control.h" +// already included above +// #include "rosidl_runtime_c/message_type_support_struct.h" +// already included above +// #include "rosidl_runtime_c/service_type_support_struct.h" +// already included above +// #include "rosidl_runtime_c/action_type_support_struct.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__type_support.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__struct.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__functions.h" + +static void * example_msgs__srv__custom_call__response__create_ros_message(void) +{ + return example_msgs__srv__CustomCall_Response__create(); +} + +static void example_msgs__srv__custom_call__response__destroy_ros_message(void * raw_ros_message) +{ + example_msgs__srv__CustomCall_Response * ros_message = (example_msgs__srv__CustomCall_Response *)raw_ros_message; + example_msgs__srv__CustomCall_Response__destroy(ros_message); +} + +ROSIDL_GENERATOR_C_IMPORT +bool example_msgs__srv__custom_call__response__convert_from_py(PyObject * _pymsg, void * ros_message); +ROSIDL_GENERATOR_C_IMPORT +PyObject * example_msgs__srv__custom_call__response__convert_to_py(void * raw_ros_message); + + +ROSIDL_GENERATOR_C_IMPORT +const rosidl_message_type_support_t * +ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Response); + +int8_t +_register_msg_type__srv__custom_call__response(PyObject * pymodule) +{ + int8_t err; + + PyObject * pyobject_create_ros_message = NULL; + pyobject_create_ros_message = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__response__create_ros_message, + NULL, NULL); + if (!pyobject_create_ros_message) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "create_ros_message_msg__srv__custom_call__response", + pyobject_create_ros_message); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_create_ros_message); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_destroy_ros_message = NULL; + pyobject_destroy_ros_message = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__response__destroy_ros_message, + NULL, NULL); + if (!pyobject_destroy_ros_message) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "destroy_ros_message_msg__srv__custom_call__response", + pyobject_destroy_ros_message); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_destroy_ros_message); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_convert_from_py = NULL; + pyobject_convert_from_py = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__response__convert_from_py, + NULL, NULL); + if (!pyobject_convert_from_py) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "convert_from_py_msg__srv__custom_call__response", + pyobject_convert_from_py); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_convert_from_py); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_convert_to_py = NULL; + pyobject_convert_to_py = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__response__convert_to_py, + NULL, NULL); + if (!pyobject_convert_to_py) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "convert_to_py_msg__srv__custom_call__response", + pyobject_convert_to_py); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_convert_to_py); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_type_support = NULL; + pyobject_type_support = PyCapsule_New( + (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Response), + NULL, NULL); + if (!pyobject_type_support) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "type_support_msg__srv__custom_call__response", + pyobject_type_support); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_type_support); + // previously added objects will be removed when the module is destroyed + return err; + } + return 0; +} + +// already included above +// #include +// already included above +// #include +// already included above +// #include "rosidl_runtime_c/visibility_control.h" +// already included above +// #include "rosidl_runtime_c/message_type_support_struct.h" +// already included above +// #include "rosidl_runtime_c/service_type_support_struct.h" +// already included above +// #include "rosidl_runtime_c/action_type_support_struct.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__type_support.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__struct.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__functions.h" + +static void * example_msgs__srv__custom_call__event__create_ros_message(void) +{ + return example_msgs__srv__CustomCall_Event__create(); +} + +static void example_msgs__srv__custom_call__event__destroy_ros_message(void * raw_ros_message) +{ + example_msgs__srv__CustomCall_Event * ros_message = (example_msgs__srv__CustomCall_Event *)raw_ros_message; + example_msgs__srv__CustomCall_Event__destroy(ros_message); +} + +ROSIDL_GENERATOR_C_IMPORT +bool example_msgs__srv__custom_call__event__convert_from_py(PyObject * _pymsg, void * ros_message); +ROSIDL_GENERATOR_C_IMPORT +PyObject * example_msgs__srv__custom_call__event__convert_to_py(void * raw_ros_message); + + +ROSIDL_GENERATOR_C_IMPORT +const rosidl_message_type_support_t * +ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Event); + +int8_t +_register_msg_type__srv__custom_call__event(PyObject * pymodule) +{ + int8_t err; + + PyObject * pyobject_create_ros_message = NULL; + pyobject_create_ros_message = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__event__create_ros_message, + NULL, NULL); + if (!pyobject_create_ros_message) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "create_ros_message_msg__srv__custom_call__event", + pyobject_create_ros_message); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_create_ros_message); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_destroy_ros_message = NULL; + pyobject_destroy_ros_message = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__event__destroy_ros_message, + NULL, NULL); + if (!pyobject_destroy_ros_message) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "destroy_ros_message_msg__srv__custom_call__event", + pyobject_destroy_ros_message); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_destroy_ros_message); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_convert_from_py = NULL; + pyobject_convert_from_py = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__event__convert_from_py, + NULL, NULL); + if (!pyobject_convert_from_py) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "convert_from_py_msg__srv__custom_call__event", + pyobject_convert_from_py); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_convert_from_py); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_convert_to_py = NULL; + pyobject_convert_to_py = PyCapsule_New( + (void *)&example_msgs__srv__custom_call__event__convert_to_py, + NULL, NULL); + if (!pyobject_convert_to_py) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "convert_to_py_msg__srv__custom_call__event", + pyobject_convert_to_py); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_convert_to_py); + // previously added objects will be removed when the module is destroyed + return err; + } + + PyObject * pyobject_type_support = NULL; + pyobject_type_support = PyCapsule_New( + (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Event), + NULL, NULL); + if (!pyobject_type_support) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "type_support_msg__srv__custom_call__event", + pyobject_type_support); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_type_support); + // previously added objects will be removed when the module is destroyed + return err; + } + return 0; +} + +ROSIDL_GENERATOR_C_IMPORT +const rosidl_service_type_support_t * +ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, example_msgs, srv, CustomCall)(); + +int8_t +_register_srv_type__srv__custom_call(PyObject * pymodule) +{ + int8_t err; + PyObject * pyobject_type_support = NULL; + pyobject_type_support = PyCapsule_New( + (void *)ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, example_msgs, srv, CustomCall)(), + NULL, NULL); + if (!pyobject_type_support) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "type_support_srv__srv__custom_call", + pyobject_type_support); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_type_support); + // previously added objects will be removed when the module is destroyed + return err; + } + return 0; +} + +#include "./_example_msgs_decl.h" + +static PyMethodDef example_msgs__methods[] = { + {NULL, NULL, 0, NULL} /* sentinel */ +}; + +static int +_example_msgs_clear(PyObject * module) +{ + (void)module; + example_msgs__lazy_import_release(); + return 0; +} + +static void +_example_msgs_free(void * module) +{ + _example_msgs_clear((PyObject *)module); +} + + +static struct PyModuleDef example_msgs__module = { + PyModuleDef_HEAD_INIT, + "_example_msgs_support", + "_example_msgs_doc", + -1, /* -1 means that the module keeps state in global variables */ + example_msgs__methods, + NULL, + NULL, + _example_msgs_clear, + _example_msgs_free, +}; + + +PyMODINIT_FUNC +PyInit_example_msgs_s__rosidl_typesupport_c(void) +{ + PyObject * pymodule = NULL; + pymodule = PyModule_Create(&example_msgs__module); + if (!pymodule) { + return NULL; + } + int8_t err; + + err = _register_msg_type__msg__custom_message(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_msg_type__srv__custom_call__request(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_msg_type__srv__custom_call__response(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_msg_type__srv__custom_call__event(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_srv_type__srv__custom_call(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + example_msgs__lazy_import_acquire(); + return pymodule; +} diff --git a/rosidl_generator_py/example/msg/CustomMessage.msg b/rosidl_generator_py/example/msg/CustomMessage.msg new file mode 100644 index 00000000..d54d663b --- /dev/null +++ b/rosidl_generator_py/example/msg/CustomMessage.msg @@ -0,0 +1,5 @@ +uint16 x +builtin_interfaces/Time ts +int16[3] fixed_seq +int16[<=3] limited_seq +int16[] unlimited_seq diff --git a/rosidl_generator_py/example/msg/__init__.py b/rosidl_generator_py/example/msg/__init__.py new file mode 100644 index 00000000..a2b9271b --- /dev/null +++ b/rosidl_generator_py/example/msg/__init__.py @@ -0,0 +1 @@ +from example_msgs.msg._custom_message import CustomMessage # noqa: F401 diff --git a/rosidl_generator_py/example/msg/_custom_message.py b/rosidl_generator_py/example/msg/_custom_message.py new file mode 100644 index 00000000..703e4123 --- /dev/null +++ b/rosidl_generator_py/example/msg/_custom_message.py @@ -0,0 +1,291 @@ +# generated from rosidl_generator_py/resource/_idl.py.em +# with input from example_msgs:msg/CustomMessage.idl +# generated code does not contain a copyright notice + + +# Import statements for member types + +# Member 'limited_seq' +# Member 'unlimited_seq' +import array # noqa: E402, I100 + +import builtins # noqa: E402, I100 + +import example_msgs._example_msgs_bases as _bases # noqa: E402, I100 + +# Member 'fixed_seq' +import numpy # noqa: E402, I100 + +import rosidl_parser.definition # noqa: E402, I100 + + +class Metaclass_CustomMessage(type): + """Metaclass of message 'CustomMessage'.""" + + _CREATE_ROS_MESSAGE = None + _CONVERT_FROM_PY = None + _CONVERT_TO_PY = None + _DESTROY_ROS_MESSAGE = None + _TYPE_SUPPORT = None + + __constants = { + } + + def __new__(cls, *args): + new_type = super().__new__(cls, *args) + + # Ugly hack here. + # There are two purposes for __slots__ field of message class: + # 1) __slots__ field is used in ROS as a list of message members. + # Number of ROS packages rely on its value. + # 2) defining __slots__ in Python class prevents adding __dict__ + # to class instances. This behvior is desirable. + # If #1 defined in message class body, then base class member descriptors are + # overriden and no longer can be used. On the other side, any __slots__ value + # should be defined to guaratee #2. + # So we define empty list in message class body and modify it after type object + # constructed. This is neither prohibited, nor encouraged by CPython documentation. + new_type.__slots__ += [ + '_x', + '_ts', + '_fixed_seq', + '_limited_seq', + '_unlimited_seq', + ] + return new_type + + @classmethod + def __import_type_support__(cls): + try: + from rosidl_generator_py import import_type_support + module = import_type_support('example_msgs') + except ImportError: + import logging + import traceback + logger = logging.getLogger( + 'example_msgs.msg.CustomMessage') + logger.debug( + 'Failed to import needed modules for type support:\n' + + traceback.format_exc()) + else: + cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__msg__custom_message + cls._CONVERT_FROM_PY = module.convert_from_py_msg__msg__custom_message + cls._CONVERT_TO_PY = module.convert_to_py_msg__msg__custom_message + cls._TYPE_SUPPORT = module.type_support_msg__msg__custom_message + cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__msg__custom_message + + from builtin_interfaces.msg import Time + if Time.__class__._TYPE_SUPPORT is None: + Time.__class__.__import_type_support__() + + @classmethod + def __prepare__(cls, name, bases, **kwargs): + # list constant names here so that they appear in the help text of + # the message class under "Data and other attributes defined here:" + # as well as populate each message instance + return { + } + + +class CustomMessage(_bases.CustomMessageBase, metaclass=Metaclass_CustomMessage): + """Message class 'CustomMessage'.""" + + # This field is modified after class creation. + # See the comment to Metaclass_CustomMessage.__new__ + __slots__ = [] + + _fields_and_field_types = { + 'x': 'uint16', + 'ts': 'builtin_interfaces/Time', + 'fixed_seq': 'int16[3]', + 'limited_seq': 'sequence', + 'unlimited_seq': 'sequence', + } + + SLOT_TYPES = ( + rosidl_parser.definition.BasicType('uint16'), # noqa: E501 + rosidl_parser.definition.NamespacedType(['builtin_interfaces', 'msg'], 'Time'), # noqa: E501 + rosidl_parser.definition.Array(rosidl_parser.definition.BasicType('int16'), 3), # noqa: E501 + rosidl_parser.definition.BoundedSequence(rosidl_parser.definition.BasicType('int16'), 3), # noqa: E501 + rosidl_parser.definition.UnboundedSequence(rosidl_parser.definition.BasicType('int16')), # noqa: E501 + ) + + 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__)) + self.x = kwargs.get('x', int()) + from builtin_interfaces.msg import Time + self.ts = kwargs.get('ts', Time()) + if 'fixed_seq' not in kwargs: + self.fixed_seq = numpy.zeros(3, dtype=numpy.int16) + else: + self.fixed_seq = numpy.array(kwargs.get('fixed_seq'), dtype=numpy.int16) + assert self.fixed_seq.shape == (3, ) + self.limited_seq = array.array('h', kwargs.get('limited_seq', [])) + self.unlimited_seq = array.array('h', kwargs.get('unlimited_seq', [])) + + def __repr__(self): + typename = self.__class__.__module__.split('.') + typename.pop() + typename.append(self.__class__.__name__) + args = [] + for s, t in zip(self.__slots__, self.SLOT_TYPES): + field = getattr(self, s) + fieldstr = repr(field) + # We use Python array type for fields that can be directly stored + # in them, and "normal" sequences for everything else. If it is + # a type that we store in an array, strip off the 'array' portion. + if ( + isinstance(t, rosidl_parser.definition.AbstractSequence) and + isinstance(t.value_type, rosidl_parser.definition.BasicType) and + t.value_type.typename in ['float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] + ): + if len(field) == 0: + fieldstr = '[]' + else: + assert fieldstr.startswith('array(') + prefix = "array('X', " + suffix = ')' + fieldstr = fieldstr[len(prefix):-len(suffix)] + args.append(s[1:] + '=' + fieldstr) + return '%s(%s)' % ('.'.join(typename), ', '.join(args)) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + if self.x != other.x: + return False + if self.ts != other.ts: + return False + if all(self.fixed_seq != other.fixed_seq): + return False + if self.limited_seq != other.limited_seq: + return False + if self.unlimited_seq != other.unlimited_seq: + return False + return True + + @classmethod + def get_fields_and_field_types(cls): + from copy import copy + return copy(cls._fields_and_field_types) + + @builtins.property + def x(self): + """Message field 'x'.""" + return self._x + + @x.setter + def x(self, value): + if __debug__: + assert \ + isinstance(value, int), \ + "The 'x' field must be of type 'int'" + assert value >= 0 and value < 65536, \ + "The 'x' field must be an unsigned integer in [0, 65535]" + self._x = value + + @builtins.property + def ts(self): + """Message field 'ts'.""" + return self._ts + + @ts.setter + def ts(self, value): + if __debug__: + from builtin_interfaces.msg import Time + assert \ + isinstance(value, Time), \ + "The 'ts' field must be a sub message of type 'Time'" + self._ts = value + + @builtins.property + def fixed_seq(self): + """Message field 'fixed_seq'.""" + return self._fixed_seq + + @fixed_seq.setter + def fixed_seq(self, value): + if isinstance(value, numpy.ndarray): + assert value.dtype == numpy.int16, \ + "The 'fixed_seq' numpy.ndarray() must have the dtype of 'numpy.int16'" + assert value.size == 3, \ + "The 'fixed_seq' numpy.ndarray() must have a size of 3" + self._fixed_seq = value + return + if __debug__: + from collections.abc import Sequence + from collections.abc import Set + from collections import UserList + from collections import UserString + assert \ + ((isinstance(value, Sequence) or + isinstance(value, Set) or + isinstance(value, UserList)) and + not isinstance(value, str) and + not isinstance(value, UserString) and + len(value) == 3 and + all(isinstance(v, int) for v in value) and + all(val >= -32768 and val < 32768 for val in value)), \ + "The 'fixed_seq' field must be a set or sequence with length 3 and each value of type 'int' and each integer in [-32768, 32767]" + self._fixed_seq = numpy.array(value, dtype=numpy.int16) + + @builtins.property + def limited_seq(self): + """Message field 'limited_seq'.""" + return self._limited_seq + + @limited_seq.setter + def limited_seq(self, value): + if isinstance(value, array.array): + assert value.typecode == 'h', \ + "The 'limited_seq' array.array() must have the type code of 'h'" + assert len(value) <= 3, \ + "The 'limited_seq' array.array() must have a size <= 3" + self._limited_seq = value + return + if __debug__: + from collections.abc import Sequence + from collections.abc import Set + from collections import UserList + from collections import UserString + assert \ + ((isinstance(value, Sequence) or + isinstance(value, Set) or + isinstance(value, UserList)) and + not isinstance(value, str) and + not isinstance(value, UserString) and + len(value) <= 3 and + all(isinstance(v, int) for v in value) and + all(val >= -32768 and val < 32768 for val in value)), \ + "The 'limited_seq' field must be a set or sequence with length <= 3 and each value of type 'int' and each integer in [-32768, 32767]" + self._limited_seq = array.array('h', value) + + @builtins.property + def unlimited_seq(self): + """Message field 'unlimited_seq'.""" + return self._unlimited_seq + + @unlimited_seq.setter + def unlimited_seq(self, value): + if isinstance(value, array.array): + assert value.typecode == 'h', \ + "The 'unlimited_seq' array.array() must have the type code of 'h'" + self._unlimited_seq = value + return + if __debug__: + from collections.abc import Sequence + from collections.abc import Set + from collections import UserList + from collections import UserString + assert \ + ((isinstance(value, Sequence) or + isinstance(value, Set) or + isinstance(value, UserList)) and + not isinstance(value, str) and + not isinstance(value, UserString) and + all(isinstance(v, int) for v in value) and + all(val >= -32768 and val < 32768 for val in value)), \ + "The 'unlimited_seq' field must be a set or sequence and each value of type 'int' and each integer in [-32768, 32767]" + self._unlimited_seq = array.array('h', value) diff --git a/rosidl_generator_py/example/msg/_custom_message_s.c b/rosidl_generator_py/example/msg/_custom_message_s.c new file mode 100644 index 00000000..97e84d93 --- /dev/null +++ b/rosidl_generator_py/example/msg/_custom_message_s.c @@ -0,0 +1,386 @@ +// generated from rosidl_generator_py/resource/_idl_support.c.em +// with input from example_msgs:msg/CustomMessage.idl +// generated code does not contain a copyright notice +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include +#include +#ifndef _WIN32 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-function" +#endif +#include "numpy/ndarrayobject.h" +#ifndef _WIN32 +# pragma GCC diagnostic pop +#endif +#include "rosidl_runtime_c/visibility_control.h" +#include "example_msgs/msg/detail/custom_message__struct.h" +#include "example_msgs/msg/detail/custom_message__functions.h" +#include "../_example_msgs_decl.h" + +#include "rosidl_runtime_c/primitives_sequence.h" +#include "rosidl_runtime_c/primitives_sequence_functions.h" + +ROSIDL_GENERATOR_C_IMPORT +bool builtin_interfaces__msg__time__convert_from_py(PyObject * _pymsg, void * _ros_message); +ROSIDL_GENERATOR_C_IMPORT +PyObject * builtin_interfaces__msg__time__convert_to_py(void * raw_ros_message); + +ROSIDL_GENERATOR_C_EXPORT +bool example_msgs__msg__custom_message__convert_from_py(PyObject * _pymsg, void * _ros_message) +{ + // check that the passed message is of the expected Python class + { + PyTypeObject * py_type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__MSG__CUSTOM_MESSAGE__IMPORT_INDEX); + assert(Py_TYPE(_pymsg) == py_type); + } + example_msgs__msg__CustomMessage * ros_message = _ros_message; + + CustomMessageBase * base_msg = (CustomMessageBase *)_pymsg; + { // x + ros_message->x = base_msg->_x; + } + { // ts + PyObject * field = base_msg->_ts; + if (!field) { + return false; + } + if (!builtin_interfaces__msg__time__convert_from_py(field, &ros_message->ts)) { + return false; + } + } + { // fixed_seq + PyObject * field = base_msg->_fixed_seq; + if (!field) { + return false; + } + { + // TODO(dirk-thomas) use a better way to check the type before casting + assert(field->ob_type != NULL); + assert(field->ob_type->tp_name != NULL); + assert(strcmp(field->ob_type->tp_name, "numpy.ndarray") == 0); + PyArrayObject * seq_field = (PyArrayObject *)field; + Py_INCREF(seq_field); + assert(PyArray_NDIM(seq_field) == 1); + assert(PyArray_TYPE(seq_field) == NPY_INT16); + Py_ssize_t size = 3; + int16_t * dest = ros_message->fixed_seq; + for (Py_ssize_t i = 0; i < size; ++i) { + int16_t tmp = *(npy_int16 *)PyArray_GETPTR1(seq_field, i); + memcpy(&dest[i], &tmp, sizeof(int16_t)); + } + Py_DECREF(seq_field); + } + } + { // limited_seq + PyObject * field = base_msg->_limited_seq; + if (!field) { + return false; + } + if (PyObject_CheckBuffer(field)) { + // Optimization for converting arrays of primitives + Py_buffer view; + int rc = PyObject_GetBuffer(field, &view, PyBUF_SIMPLE); + if (rc < 0) { + return false; + } + Py_ssize_t size = view.len / sizeof(int16_t); + if (!rosidl_runtime_c__int16__Sequence__init(&(ros_message->limited_seq), size)) { + PyErr_SetString(PyExc_RuntimeError, "unable to create int16__Sequence ros_message"); + PyBuffer_Release(&view); + return false; + } + int16_t * dest = ros_message->limited_seq.data; + rc = PyBuffer_ToContiguous(dest, &view, view.len, 'C'); + if (rc < 0) { + PyBuffer_Release(&view); + return false; + } + PyBuffer_Release(&view); + } else { + PyObject * seq_field = PySequence_Fast(field, "expected a sequence in 'limited_seq'"); + if (!seq_field) { + return false; + } + Py_ssize_t size = PySequence_Size(field); + if (-1 == size) { + Py_DECREF(seq_field); + return false; + } + if (!rosidl_runtime_c__int16__Sequence__init(&(ros_message->limited_seq), size)) { + PyErr_SetString(PyExc_RuntimeError, "unable to create int16__Sequence ros_message"); + Py_DECREF(seq_field); + return false; + } + int16_t * dest = ros_message->limited_seq.data; + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject * item = PySequence_Fast_GET_ITEM(seq_field, i); + if (!item) { + Py_DECREF(seq_field); + return false; + } + assert(PyLong_Check(item)); + int16_t tmp = (int16_t)PyLong_AsLong(item); + memcpy(&dest[i], &tmp, sizeof(int16_t)); + } + Py_DECREF(seq_field); + } + } + { // unlimited_seq + PyObject * field = base_msg->_unlimited_seq; + if (!field) { + return false; + } + if (PyObject_CheckBuffer(field)) { + // Optimization for converting arrays of primitives + Py_buffer view; + int rc = PyObject_GetBuffer(field, &view, PyBUF_SIMPLE); + if (rc < 0) { + return false; + } + Py_ssize_t size = view.len / sizeof(int16_t); + if (!rosidl_runtime_c__int16__Sequence__init(&(ros_message->unlimited_seq), size)) { + PyErr_SetString(PyExc_RuntimeError, "unable to create int16__Sequence ros_message"); + PyBuffer_Release(&view); + return false; + } + int16_t * dest = ros_message->unlimited_seq.data; + rc = PyBuffer_ToContiguous(dest, &view, view.len, 'C'); + if (rc < 0) { + PyBuffer_Release(&view); + return false; + } + PyBuffer_Release(&view); + } else { + PyObject * seq_field = PySequence_Fast(field, "expected a sequence in 'unlimited_seq'"); + if (!seq_field) { + return false; + } + Py_ssize_t size = PySequence_Size(field); + if (-1 == size) { + Py_DECREF(seq_field); + return false; + } + if (!rosidl_runtime_c__int16__Sequence__init(&(ros_message->unlimited_seq), size)) { + PyErr_SetString(PyExc_RuntimeError, "unable to create int16__Sequence ros_message"); + Py_DECREF(seq_field); + return false; + } + int16_t * dest = ros_message->unlimited_seq.data; + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject * item = PySequence_Fast_GET_ITEM(seq_field, i); + if (!item) { + Py_DECREF(seq_field); + return false; + } + assert(PyLong_Check(item)); + int16_t tmp = (int16_t)PyLong_AsLong(item); + memcpy(&dest[i], &tmp, sizeof(int16_t)); + } + Py_DECREF(seq_field); + } + } + + return true; +} + +ROSIDL_GENERATOR_C_EXPORT +PyObject * example_msgs__msg__custom_message__convert_to_py(void * raw_ros_message) +{ + /* NOTE(esteve): Call constructor of CustomMessage */ + CustomMessageBase * _pymessage = NULL; + { + PyTypeObject * type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__MSG__CUSTOM_MESSAGE__IMPORT_INDEX); + if (!type) { + return NULL; + } + assert(type->tp_new); + + PyObject * empty_tuple = PyTuple_New(0); + if (!empty_tuple) { + return NULL; + } + + _pymessage = (CustomMessageBase *)type->tp_new(type, empty_tuple, NULL); + Py_DECREF(empty_tuple); + if (!_pymessage) { + return NULL; + } + } + example_msgs__msg__CustomMessage * ros_message = (example_msgs__msg__CustomMessage *)raw_ros_message; + { // x + _pymessage->_x = ros_message->x; + } + { // ts + PyObject * field = NULL; + field = builtin_interfaces__msg__time__convert_to_py(&ros_message->ts); + if (!field) { + return NULL; + } + // reference is transfered to object + _pymessage->_ts = field; + } + { // fixed_seq + PyObject * field = NULL; + + PyObject * array_type = example_msgs__lazy_import(NULL, NUMPY__NDARRAY__IMPORT_INDEX); + if (!array_type) { + return NULL; + } + PyObject * element_type = example_msgs__lazy_import(NULL, NUMPY__INT16__IMPORT_INDEX); + if (!element_type) { + return NULL; + } + PyObject * dims = Py_BuildValue("(i)", 3); + field = PyObject_CallFunctionObjArgs(array_type, dims, element_type, NULL); + Py_DECREF(dims); + assert(strcmp(field->ob_type->tp_name, "numpy.ndarray") == 0); + PyArrayObject * seq_field = (PyArrayObject *)field; + assert(PyArray_NDIM(seq_field) == 1); + assert(PyArray_TYPE(seq_field) == NPY_INT16); + assert(sizeof(npy_int16) == sizeof(int16_t)); + npy_int16 * dst = (npy_int16 *)PyArray_GETPTR1(seq_field, 0); + int16_t * src = &(ros_message->fixed_seq[0]); + memcpy(dst, src, 3 * sizeof(int16_t)); + // reference is transfered to object + _pymessage->_fixed_seq = field; + } + { // limited_seq + PyObject * field = NULL; + { + PyObject * array_type = example_msgs__lazy_import(NULL, ARRAY__ARRAY__IMPORT_INDEX); + if (!array_type) { + return NULL; + } + PyObject * type_code = PyUnicode_FromOrdinal('h'); + assert(type_code); + + field = PyObject_CallFunctionObjArgs(array_type, type_code, NULL); + Py_DECREF(type_code); + if (!field) { + return NULL; + } + } + assert(field->ob_type != NULL); + assert(field->ob_type->tp_name != NULL); + assert(strcmp(field->ob_type->tp_name, "array.array") == 0); + // ensure that itemsize matches the sizeof of the ROS message field + PyObject * itemsize_attr = PyObject_GetAttrString(field, "itemsize"); + assert(itemsize_attr != NULL); + size_t itemsize = PyLong_AsSize_t(itemsize_attr); + Py_DECREF(itemsize_attr); + if (itemsize != sizeof(int16_t)) { + PyErr_SetString(PyExc_RuntimeError, "itemsize doesn't match expectation"); + Py_DECREF(field); + return NULL; + } + // clear the array, poor approach to remove potential default values + Py_ssize_t length = PyObject_Length(field); + if (-1 == length) { + Py_DECREF(field); + return NULL; + } + if (length > 0) { + PyObject * pop = PyObject_GetAttrString(field, "pop"); + assert(pop != NULL); + for (Py_ssize_t i = 0; i < length; ++i) { + PyObject * ret = PyObject_CallFunctionObjArgs(pop, NULL); + if (!ret) { + Py_DECREF(pop); + Py_DECREF(field); + return NULL; + } + Py_DECREF(ret); + } + Py_DECREF(pop); + } + if (ros_message->limited_seq.size > 0) { + // populating the array.array using the frombytes method + PyObject * frombytes = PyObject_GetAttrString(field, "frombytes"); + assert(frombytes != NULL); + int16_t * src = &(ros_message->limited_seq.data[0]); + PyObject * data = PyBytes_FromStringAndSize((const char *)src, ros_message->limited_seq.size * sizeof(int16_t)); + assert(data != NULL); + PyObject * ret = PyObject_CallFunctionObjArgs(frombytes, data, NULL); + Py_DECREF(data); + Py_DECREF(frombytes); + if (!ret) { + Py_DECREF(field); + return NULL; + } + Py_DECREF(ret); + } + // reference is transfered to object + _pymessage->_limited_seq = field; + } + { // unlimited_seq + PyObject * field = NULL; + { + PyObject * array_type = example_msgs__lazy_import(NULL, ARRAY__ARRAY__IMPORT_INDEX); + if (!array_type) { + return NULL; + } + PyObject * type_code = PyUnicode_FromOrdinal('h'); + assert(type_code); + + field = PyObject_CallFunctionObjArgs(array_type, type_code, NULL); + Py_DECREF(type_code); + if (!field) { + return NULL; + } + } + assert(field->ob_type != NULL); + assert(field->ob_type->tp_name != NULL); + assert(strcmp(field->ob_type->tp_name, "array.array") == 0); + // ensure that itemsize matches the sizeof of the ROS message field + PyObject * itemsize_attr = PyObject_GetAttrString(field, "itemsize"); + assert(itemsize_attr != NULL); + size_t itemsize = PyLong_AsSize_t(itemsize_attr); + Py_DECREF(itemsize_attr); + if (itemsize != sizeof(int16_t)) { + PyErr_SetString(PyExc_RuntimeError, "itemsize doesn't match expectation"); + Py_DECREF(field); + return NULL; + } + // clear the array, poor approach to remove potential default values + Py_ssize_t length = PyObject_Length(field); + if (-1 == length) { + Py_DECREF(field); + return NULL; + } + if (length > 0) { + PyObject * pop = PyObject_GetAttrString(field, "pop"); + assert(pop != NULL); + for (Py_ssize_t i = 0; i < length; ++i) { + PyObject * ret = PyObject_CallFunctionObjArgs(pop, NULL); + if (!ret) { + Py_DECREF(pop); + Py_DECREF(field); + return NULL; + } + Py_DECREF(ret); + } + Py_DECREF(pop); + } + if (ros_message->unlimited_seq.size > 0) { + // populating the array.array using the frombytes method + PyObject * frombytes = PyObject_GetAttrString(field, "frombytes"); + assert(frombytes != NULL); + int16_t * src = &(ros_message->unlimited_seq.data[0]); + PyObject * data = PyBytes_FromStringAndSize((const char *)src, ros_message->unlimited_seq.size * sizeof(int16_t)); + assert(data != NULL); + PyObject * ret = PyObject_CallFunctionObjArgs(frombytes, data, NULL); + Py_DECREF(data); + Py_DECREF(frombytes); + if (!ret) { + Py_DECREF(field); + return NULL; + } + Py_DECREF(ret); + } + // reference is transfered to object + _pymessage->_unlimited_seq = field; + } + + // ownership of _pymessage is transferred to the caller + return (PyObject *)_pymessage; +} diff --git a/rosidl_generator_py/example/srv/CustomCall.srv b/rosidl_generator_py/example/srv/CustomCall.srv new file mode 100644 index 00000000..1ab4c8a2 --- /dev/null +++ b/rosidl_generator_py/example/srv/CustomCall.srv @@ -0,0 +1,3 @@ +int32 my_param +--- +int32 my_result diff --git a/rosidl_generator_py/example/srv/__init__.py b/rosidl_generator_py/example/srv/__init__.py new file mode 100644 index 00000000..1340e40c --- /dev/null +++ b/rosidl_generator_py/example/srv/__init__.py @@ -0,0 +1,4 @@ +from example_msgs.srv._custom_call import CustomCall # noqa: F401 +from example_msgs.srv._custom_call import CustomCall_Event # noqa: F401 +from example_msgs.srv._custom_call import CustomCall_Request # noqa: F401 +from example_msgs.srv._custom_call import CustomCall_Response # noqa: F401 diff --git a/rosidl_generator_py/example/srv/_custom_call.py b/rosidl_generator_py/example/srv/_custom_call.py new file mode 100644 index 00000000..2d16faca --- /dev/null +++ b/rosidl_generator_py/example/srv/_custom_call.py @@ -0,0 +1,546 @@ +# generated from rosidl_generator_py/resource/_idl.py.em +# with input from example_msgs:srv/CustomCall.idl +# generated code does not contain a copyright notice + + +# Import statements for member types + +import builtins # noqa: E402, I100 + +import example_msgs._example_msgs_bases as _bases # noqa: E402, I100 + +import rosidl_parser.definition # noqa: E402, I100 + + +class Metaclass_CustomCall_Request(type): + """Metaclass of message 'CustomCall_Request'.""" + + _CREATE_ROS_MESSAGE = None + _CONVERT_FROM_PY = None + _CONVERT_TO_PY = None + _DESTROY_ROS_MESSAGE = None + _TYPE_SUPPORT = None + + __constants = { + } + + def __new__(cls, *args): + new_type = super().__new__(cls, *args) + + # Ugly hack here. + # There are two purposes for __slots__ field of message class: + # 1) __slots__ field is used in ROS as a list of message members. + # Number of ROS packages rely on its value. + # 2) defining __slots__ in Python class prevents adding __dict__ + # to class instances. This behvior is desirable. + # If #1 defined in message class body, then base class member descriptors are + # overriden and no longer can be used. On the other side, any __slots__ value + # should be defined to guaratee #2. + # So we define empty list in message class body and modify it after type object + # constructed. This is neither prohibited, nor encouraged by CPython documentation. + new_type.__slots__ += [ + '_my_param', + ] + return new_type + + @classmethod + def __import_type_support__(cls): + try: + from rosidl_generator_py import import_type_support + module = import_type_support('example_msgs') + except ImportError: + import logging + import traceback + logger = logging.getLogger( + 'example_msgs.srv.CustomCall_Request') + logger.debug( + 'Failed to import needed modules for type support:\n' + + traceback.format_exc()) + else: + cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__srv__custom_call__request + cls._CONVERT_FROM_PY = module.convert_from_py_msg__srv__custom_call__request + cls._CONVERT_TO_PY = module.convert_to_py_msg__srv__custom_call__request + cls._TYPE_SUPPORT = module.type_support_msg__srv__custom_call__request + cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__srv__custom_call__request + + @classmethod + def __prepare__(cls, name, bases, **kwargs): + # list constant names here so that they appear in the help text of + # the message class under "Data and other attributes defined here:" + # as well as populate each message instance + return { + } + + +class CustomCall_Request(_bases.CustomCall_RequestBase, metaclass=Metaclass_CustomCall_Request): + """Message class 'CustomCall_Request'.""" + + # This field is modified after class creation. + # See the comment to Metaclass_CustomCall_Request.__new__ + __slots__ = [] + + _fields_and_field_types = { + 'my_param': 'int32', + } + + SLOT_TYPES = ( + rosidl_parser.definition.BasicType('int32'), # noqa: E501 + ) + + 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__)) + self.my_param = kwargs.get('my_param', int()) + + def __repr__(self): + typename = self.__class__.__module__.split('.') + typename.pop() + typename.append(self.__class__.__name__) + args = [] + for s, t in zip(self.__slots__, self.SLOT_TYPES): + field = getattr(self, s) + fieldstr = repr(field) + # We use Python array type for fields that can be directly stored + # in them, and "normal" sequences for everything else. If it is + # a type that we store in an array, strip off the 'array' portion. + if ( + isinstance(t, rosidl_parser.definition.AbstractSequence) and + isinstance(t.value_type, rosidl_parser.definition.BasicType) and + t.value_type.typename in ['float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] + ): + if len(field) == 0: + fieldstr = '[]' + else: + assert fieldstr.startswith('array(') + prefix = "array('X', " + suffix = ')' + fieldstr = fieldstr[len(prefix):-len(suffix)] + args.append(s[1:] + '=' + fieldstr) + return '%s(%s)' % ('.'.join(typename), ', '.join(args)) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + if self.my_param != other.my_param: + return False + return True + + @classmethod + def get_fields_and_field_types(cls): + from copy import copy + return copy(cls._fields_and_field_types) + + @builtins.property + def my_param(self): + """Message field 'my_param'.""" + return self._my_param + + @my_param.setter + def my_param(self, value): + if __debug__: + assert \ + isinstance(value, int), \ + "The 'my_param' field must be of type 'int'" + assert value >= -2147483648 and value < 2147483648, \ + "The 'my_param' field must be an integer in [-2147483648, 2147483647]" + self._my_param = value + + +# Import statements for member types + +# already imported above +# import builtins + +# already imported above +# import example_msgs._example_msgs_bases as _bases + +# already imported above +# import rosidl_parser.definition + + +class Metaclass_CustomCall_Response(type): + """Metaclass of message 'CustomCall_Response'.""" + + _CREATE_ROS_MESSAGE = None + _CONVERT_FROM_PY = None + _CONVERT_TO_PY = None + _DESTROY_ROS_MESSAGE = None + _TYPE_SUPPORT = None + + __constants = { + } + + def __new__(cls, *args): + new_type = super().__new__(cls, *args) + + # Ugly hack here. + # There are two purposes for __slots__ field of message class: + # 1) __slots__ field is used in ROS as a list of message members. + # Number of ROS packages rely on its value. + # 2) defining __slots__ in Python class prevents adding __dict__ + # to class instances. This behvior is desirable. + # If #1 defined in message class body, then base class member descriptors are + # overriden and no longer can be used. On the other side, any __slots__ value + # should be defined to guaratee #2. + # So we define empty list in message class body and modify it after type object + # constructed. This is neither prohibited, nor encouraged by CPython documentation. + new_type.__slots__ += [ + '_my_result', + ] + return new_type + + @classmethod + def __import_type_support__(cls): + try: + from rosidl_generator_py import import_type_support + module = import_type_support('example_msgs') + except ImportError: + import logging + import traceback + logger = logging.getLogger( + 'example_msgs.srv.CustomCall_Response') + logger.debug( + 'Failed to import needed modules for type support:\n' + + traceback.format_exc()) + else: + cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__srv__custom_call__response + cls._CONVERT_FROM_PY = module.convert_from_py_msg__srv__custom_call__response + cls._CONVERT_TO_PY = module.convert_to_py_msg__srv__custom_call__response + cls._TYPE_SUPPORT = module.type_support_msg__srv__custom_call__response + cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__srv__custom_call__response + + @classmethod + def __prepare__(cls, name, bases, **kwargs): + # list constant names here so that they appear in the help text of + # the message class under "Data and other attributes defined here:" + # as well as populate each message instance + return { + } + + +class CustomCall_Response(_bases.CustomCall_ResponseBase, metaclass=Metaclass_CustomCall_Response): + """Message class 'CustomCall_Response'.""" + + # This field is modified after class creation. + # See the comment to Metaclass_CustomCall_Response.__new__ + __slots__ = [] + + _fields_and_field_types = { + 'my_result': 'int32', + } + + SLOT_TYPES = ( + rosidl_parser.definition.BasicType('int32'), # noqa: E501 + ) + + 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__)) + self.my_result = kwargs.get('my_result', int()) + + def __repr__(self): + typename = self.__class__.__module__.split('.') + typename.pop() + typename.append(self.__class__.__name__) + args = [] + for s, t in zip(self.__slots__, self.SLOT_TYPES): + field = getattr(self, s) + fieldstr = repr(field) + # We use Python array type for fields that can be directly stored + # in them, and "normal" sequences for everything else. If it is + # a type that we store in an array, strip off the 'array' portion. + if ( + isinstance(t, rosidl_parser.definition.AbstractSequence) and + isinstance(t.value_type, rosidl_parser.definition.BasicType) and + t.value_type.typename in ['float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] + ): + if len(field) == 0: + fieldstr = '[]' + else: + assert fieldstr.startswith('array(') + prefix = "array('X', " + suffix = ')' + fieldstr = fieldstr[len(prefix):-len(suffix)] + args.append(s[1:] + '=' + fieldstr) + return '%s(%s)' % ('.'.join(typename), ', '.join(args)) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + if self.my_result != other.my_result: + return False + return True + + @classmethod + def get_fields_and_field_types(cls): + from copy import copy + return copy(cls._fields_and_field_types) + + @builtins.property + def my_result(self): + """Message field 'my_result'.""" + return self._my_result + + @my_result.setter + def my_result(self, value): + if __debug__: + assert \ + isinstance(value, int), \ + "The 'my_result' field must be of type 'int'" + assert value >= -2147483648 and value < 2147483648, \ + "The 'my_result' field must be an integer in [-2147483648, 2147483647]" + self._my_result = value + + +# Import statements for member types + +# already imported above +# import builtins + +# already imported above +# import example_msgs._example_msgs_bases as _bases + +# already imported above +# import rosidl_parser.definition + + +class Metaclass_CustomCall_Event(type): + """Metaclass of message 'CustomCall_Event'.""" + + _CREATE_ROS_MESSAGE = None + _CONVERT_FROM_PY = None + _CONVERT_TO_PY = None + _DESTROY_ROS_MESSAGE = None + _TYPE_SUPPORT = None + + __constants = { + } + + def __new__(cls, *args): + new_type = super().__new__(cls, *args) + + # Ugly hack here. + # There are two purposes for __slots__ field of message class: + # 1) __slots__ field is used in ROS as a list of message members. + # Number of ROS packages rely on its value. + # 2) defining __slots__ in Python class prevents adding __dict__ + # to class instances. This behvior is desirable. + # If #1 defined in message class body, then base class member descriptors are + # overriden and no longer can be used. On the other side, any __slots__ value + # should be defined to guaratee #2. + # So we define empty list in message class body and modify it after type object + # constructed. This is neither prohibited, nor encouraged by CPython documentation. + new_type.__slots__ += [ + '_info', + '_request', + '_response', + ] + return new_type + + @classmethod + def __import_type_support__(cls): + try: + from rosidl_generator_py import import_type_support + module = import_type_support('example_msgs') + except ImportError: + import logging + import traceback + logger = logging.getLogger( + 'example_msgs.srv.CustomCall_Event') + logger.debug( + 'Failed to import needed modules for type support:\n' + + traceback.format_exc()) + else: + cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__srv__custom_call__event + cls._CONVERT_FROM_PY = module.convert_from_py_msg__srv__custom_call__event + cls._CONVERT_TO_PY = module.convert_to_py_msg__srv__custom_call__event + cls._TYPE_SUPPORT = module.type_support_msg__srv__custom_call__event + cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__srv__custom_call__event + + from service_msgs.msg import ServiceEventInfo + if ServiceEventInfo.__class__._TYPE_SUPPORT is None: + ServiceEventInfo.__class__.__import_type_support__() + + @classmethod + def __prepare__(cls, name, bases, **kwargs): + # list constant names here so that they appear in the help text of + # the message class under "Data and other attributes defined here:" + # as well as populate each message instance + return { + } + + +class CustomCall_Event(_bases.CustomCall_EventBase, metaclass=Metaclass_CustomCall_Event): + """Message class 'CustomCall_Event'.""" + + # This field is modified after class creation. + # See the comment to Metaclass_CustomCall_Event.__new__ + __slots__ = [] + + _fields_and_field_types = { + 'info': 'service_msgs/ServiceEventInfo', + 'request': 'sequence', + 'response': 'sequence', + } + + SLOT_TYPES = ( + rosidl_parser.definition.NamespacedType(['service_msgs', 'msg'], 'ServiceEventInfo'), # noqa: E501 + rosidl_parser.definition.BoundedSequence(rosidl_parser.definition.NamespacedType(['example_msgs', 'srv'], 'CustomCall_Request'), 1), # noqa: E501 + rosidl_parser.definition.BoundedSequence(rosidl_parser.definition.NamespacedType(['example_msgs', 'srv'], 'CustomCall_Response'), 1), # noqa: E501 + ) + + 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__)) + from service_msgs.msg import ServiceEventInfo + self.info = kwargs.get('info', ServiceEventInfo()) + self.request = kwargs.get('request', []) + self.response = kwargs.get('response', []) + + def __repr__(self): + typename = self.__class__.__module__.split('.') + typename.pop() + typename.append(self.__class__.__name__) + args = [] + for s, t in zip(self.__slots__, self.SLOT_TYPES): + field = getattr(self, s) + fieldstr = repr(field) + # We use Python array type for fields that can be directly stored + # in them, and "normal" sequences for everything else. If it is + # a type that we store in an array, strip off the 'array' portion. + if ( + isinstance(t, rosidl_parser.definition.AbstractSequence) and + isinstance(t.value_type, rosidl_parser.definition.BasicType) and + t.value_type.typename in ['float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] + ): + if len(field) == 0: + fieldstr = '[]' + else: + assert fieldstr.startswith('array(') + prefix = "array('X', " + suffix = ')' + fieldstr = fieldstr[len(prefix):-len(suffix)] + args.append(s[1:] + '=' + fieldstr) + return '%s(%s)' % ('.'.join(typename), ', '.join(args)) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + if self.info != other.info: + return False + if self.request != other.request: + return False + if self.response != other.response: + return False + return True + + @classmethod + def get_fields_and_field_types(cls): + from copy import copy + return copy(cls._fields_and_field_types) + + @builtins.property + def info(self): + """Message field 'info'.""" + return self._info + + @info.setter + def info(self, value): + if __debug__: + from service_msgs.msg import ServiceEventInfo + assert \ + isinstance(value, ServiceEventInfo), \ + "The 'info' field must be a sub message of type 'ServiceEventInfo'" + self._info = value + + @builtins.property + def request(self): + """Message field 'request'.""" + return self._request + + @request.setter + def request(self, value): + if __debug__: + from example_msgs.srv import CustomCall_Request + from collections.abc import Sequence + from collections.abc import Set + from collections import UserList + from collections import UserString + assert \ + ((isinstance(value, Sequence) or + isinstance(value, Set) or + isinstance(value, UserList)) and + not isinstance(value, str) and + not isinstance(value, UserString) and + len(value) <= 1 and + all(isinstance(v, CustomCall_Request) for v in value) and + True), \ + "The 'request' field must be a set or sequence with length <= 1 and each value of type 'CustomCall_Request'" + self._request = value + + @builtins.property + def response(self): + """Message field 'response'.""" + return self._response + + @response.setter + def response(self, value): + if __debug__: + from example_msgs.srv import CustomCall_Response + from collections.abc import Sequence + from collections.abc import Set + from collections import UserList + from collections import UserString + assert \ + ((isinstance(value, Sequence) or + isinstance(value, Set) or + isinstance(value, UserList)) and + not isinstance(value, str) and + not isinstance(value, UserString) and + len(value) <= 1 and + all(isinstance(v, CustomCall_Response) for v in value) and + True), \ + "The 'response' field must be a set or sequence with length <= 1 and each value of type 'CustomCall_Response'" + self._response = value + + +class Metaclass_CustomCall(type): + """Metaclass of service 'CustomCall'.""" + + _TYPE_SUPPORT = None + + @classmethod + def __import_type_support__(cls): + try: + from rosidl_generator_py import import_type_support + module = import_type_support('example_msgs') + except ImportError: + import logging + import traceback + logger = logging.getLogger( + 'example_msgs.srv.CustomCall') + logger.debug( + 'Failed to import needed modules for type support:\n' + + traceback.format_exc()) + else: + cls._TYPE_SUPPORT = module.type_support_srv__srv__custom_call + + from example_msgs.srv import _custom_call + if _custom_call.Metaclass_CustomCall_Request._TYPE_SUPPORT is None: + _custom_call.Metaclass_CustomCall_Request.__import_type_support__() + if _custom_call.Metaclass_CustomCall_Response._TYPE_SUPPORT is None: + _custom_call.Metaclass_CustomCall_Response.__import_type_support__() + if _custom_call.Metaclass_CustomCall_Event._TYPE_SUPPORT is None: + _custom_call.Metaclass_CustomCall_Event.__import_type_support__() + + +class CustomCall(metaclass=Metaclass_CustomCall): + from example_msgs.srv._custom_call import CustomCall_Request as Request + from example_msgs.srv._custom_call import CustomCall_Response as Response + from example_msgs.srv._custom_call import CustomCall_Event as Event + + def __init__(self): + raise NotImplementedError('Service classes can not be instantiated') diff --git a/rosidl_generator_py/example/srv/_custom_call_s.c b/rosidl_generator_py/example/srv/_custom_call_s.c new file mode 100644 index 00000000..7b5c506d --- /dev/null +++ b/rosidl_generator_py/example/srv/_custom_call_s.c @@ -0,0 +1,332 @@ +// generated from rosidl_generator_py/resource/_idl_support.c.em +// with input from example_msgs:srv/CustomCall.idl +// generated code does not contain a copyright notice +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include +#include +#ifndef _WIN32 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-function" +#endif +#include "numpy/ndarrayobject.h" +#ifndef _WIN32 +# pragma GCC diagnostic pop +#endif +#include "rosidl_runtime_c/visibility_control.h" +#include "example_msgs/srv/detail/custom_call__struct.h" +#include "example_msgs/srv/detail/custom_call__functions.h" +#include "../_example_msgs_decl.h" + + +ROSIDL_GENERATOR_C_EXPORT +bool example_msgs__srv__custom_call__request__convert_from_py(PyObject * _pymsg, void * _ros_message) +{ + // check that the passed message is of the expected Python class + { + PyTypeObject * py_type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__REQUEST__IMPORT_INDEX); + assert(Py_TYPE(_pymsg) == py_type); + } + example_msgs__srv__CustomCall_Request * ros_message = _ros_message; + + CustomCall_RequestBase * base_msg = (CustomCall_RequestBase *)_pymsg; + { // my_param + ros_message->my_param = base_msg->_my_param; + } + + return true; +} + +ROSIDL_GENERATOR_C_EXPORT +PyObject * example_msgs__srv__custom_call__request__convert_to_py(void * raw_ros_message) +{ + /* NOTE(esteve): Call constructor of CustomCall_Request */ + CustomCall_RequestBase * _pymessage = NULL; + { + PyTypeObject * type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__REQUEST__IMPORT_INDEX); + if (!type) { + return NULL; + } + assert(type->tp_new); + + PyObject * empty_tuple = PyTuple_New(0); + if (!empty_tuple) { + return NULL; + } + + _pymessage = (CustomCall_RequestBase *)type->tp_new(type, empty_tuple, NULL); + Py_DECREF(empty_tuple); + if (!_pymessage) { + return NULL; + } + } + example_msgs__srv__CustomCall_Request * ros_message = (example_msgs__srv__CustomCall_Request *)raw_ros_message; + { // my_param + _pymessage->_my_param = ros_message->my_param; + } + + // ownership of _pymessage is transferred to the caller + return (PyObject *)_pymessage; +} + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +// already included above +// #include +// already included above +// #include +// already included above +// #include "numpy/ndarrayobject.h" +// already included above +// #include "rosidl_runtime_c/visibility_control.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__struct.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__functions.h" +// already included above +// #include "../_example_msgs_decl.h" + + +ROSIDL_GENERATOR_C_EXPORT +bool example_msgs__srv__custom_call__response__convert_from_py(PyObject * _pymsg, void * _ros_message) +{ + // check that the passed message is of the expected Python class + { + PyTypeObject * py_type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__RESPONSE__IMPORT_INDEX); + assert(Py_TYPE(_pymsg) == py_type); + } + example_msgs__srv__CustomCall_Response * ros_message = _ros_message; + + CustomCall_ResponseBase * base_msg = (CustomCall_ResponseBase *)_pymsg; + { // my_result + ros_message->my_result = base_msg->_my_result; + } + + return true; +} + +ROSIDL_GENERATOR_C_EXPORT +PyObject * example_msgs__srv__custom_call__response__convert_to_py(void * raw_ros_message) +{ + /* NOTE(esteve): Call constructor of CustomCall_Response */ + CustomCall_ResponseBase * _pymessage = NULL; + { + PyTypeObject * type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__RESPONSE__IMPORT_INDEX); + if (!type) { + return NULL; + } + assert(type->tp_new); + + PyObject * empty_tuple = PyTuple_New(0); + if (!empty_tuple) { + return NULL; + } + + _pymessage = (CustomCall_ResponseBase *)type->tp_new(type, empty_tuple, NULL); + Py_DECREF(empty_tuple); + if (!_pymessage) { + return NULL; + } + } + example_msgs__srv__CustomCall_Response * ros_message = (example_msgs__srv__CustomCall_Response *)raw_ros_message; + { // my_result + _pymessage->_my_result = ros_message->my_result; + } + + // ownership of _pymessage is transferred to the caller + return (PyObject *)_pymessage; +} + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +// already included above +// #include +// already included above +// #include +// already included above +// #include "numpy/ndarrayobject.h" +// already included above +// #include "rosidl_runtime_c/visibility_control.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__struct.h" +// already included above +// #include "example_msgs/srv/detail/custom_call__functions.h" +// already included above +// #include "../_example_msgs_decl.h" + +#include "rosidl_runtime_c/primitives_sequence.h" +#include "rosidl_runtime_c/primitives_sequence_functions.h" + +// Nested array functions includes + + +// end nested array functions include +ROSIDL_GENERATOR_C_IMPORT +bool service_msgs__msg__service_event_info__convert_from_py(PyObject * _pymsg, void * _ros_message); +ROSIDL_GENERATOR_C_IMPORT +PyObject * service_msgs__msg__service_event_info__convert_to_py(void * raw_ros_message); +bool example_msgs__srv__custom_call__request__convert_from_py(PyObject * _pymsg, void * _ros_message); +PyObject * example_msgs__srv__custom_call__request__convert_to_py(void * raw_ros_message); +bool example_msgs__srv__custom_call__response__convert_from_py(PyObject * _pymsg, void * _ros_message); +PyObject * example_msgs__srv__custom_call__response__convert_to_py(void * raw_ros_message); + +ROSIDL_GENERATOR_C_EXPORT +bool example_msgs__srv__custom_call__event__convert_from_py(PyObject * _pymsg, void * _ros_message) +{ + // check that the passed message is of the expected Python class + { + PyTypeObject * py_type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__EVENT__IMPORT_INDEX); + assert(Py_TYPE(_pymsg) == py_type); + } + example_msgs__srv__CustomCall_Event * ros_message = _ros_message; + + CustomCall_EventBase * base_msg = (CustomCall_EventBase *)_pymsg; + { // info + PyObject * field = base_msg->_info; + if (!field) { + return false; + } + if (!service_msgs__msg__service_event_info__convert_from_py(field, &ros_message->info)) { + return false; + } + } + { // request + PyObject * field = base_msg->_request; + if (!field) { + return false; + } + PyObject * seq_field = PySequence_Fast(field, "expected a sequence in 'request'"); + if (!seq_field) { + return false; + } + Py_ssize_t size = PySequence_Size(field); + if (-1 == size) { + Py_DECREF(seq_field); + return false; + } + if (!example_msgs__srv__CustomCall_Request__Sequence__init(&(ros_message->request), size)) { + PyErr_SetString(PyExc_RuntimeError, "unable to create example_msgs__srv__CustomCall_Request__Sequence ros_message"); + Py_DECREF(seq_field); + return false; + } + example_msgs__srv__CustomCall_Request * dest = ros_message->request.data; + for (Py_ssize_t i = 0; i < size; ++i) { + if (!example_msgs__srv__custom_call__request__convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) { + Py_DECREF(seq_field); + return false; + } + } + Py_DECREF(seq_field); + } + { // response + PyObject * field = base_msg->_response; + if (!field) { + return false; + } + PyObject * seq_field = PySequence_Fast(field, "expected a sequence in 'response'"); + if (!seq_field) { + return false; + } + Py_ssize_t size = PySequence_Size(field); + if (-1 == size) { + Py_DECREF(seq_field); + return false; + } + if (!example_msgs__srv__CustomCall_Response__Sequence__init(&(ros_message->response), size)) { + PyErr_SetString(PyExc_RuntimeError, "unable to create example_msgs__srv__CustomCall_Response__Sequence ros_message"); + Py_DECREF(seq_field); + return false; + } + example_msgs__srv__CustomCall_Response * dest = ros_message->response.data; + for (Py_ssize_t i = 0; i < size; ++i) { + if (!example_msgs__srv__custom_call__response__convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) { + Py_DECREF(seq_field); + return false; + } + } + Py_DECREF(seq_field); + } + + return true; +} + +ROSIDL_GENERATOR_C_EXPORT +PyObject * example_msgs__srv__custom_call__event__convert_to_py(void * raw_ros_message) +{ + /* NOTE(esteve): Call constructor of CustomCall_Event */ + CustomCall_EventBase * _pymessage = NULL; + { + PyTypeObject * type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__EVENT__IMPORT_INDEX); + if (!type) { + return NULL; + } + assert(type->tp_new); + + PyObject * empty_tuple = PyTuple_New(0); + if (!empty_tuple) { + return NULL; + } + + _pymessage = (CustomCall_EventBase *)type->tp_new(type, empty_tuple, NULL); + Py_DECREF(empty_tuple); + if (!_pymessage) { + return NULL; + } + } + example_msgs__srv__CustomCall_Event * ros_message = (example_msgs__srv__CustomCall_Event *)raw_ros_message; + { // info + PyObject * field = NULL; + field = service_msgs__msg__service_event_info__convert_to_py(&ros_message->info); + if (!field) { + return NULL; + } + // reference is transfered to object + _pymessage->_info = field; + } + { // request + PyObject * field = NULL; + size_t size = ros_message->request.size; + field = PyList_New(size); + if (!field) { + return NULL; + } + example_msgs__srv__CustomCall_Request * item; + for (size_t i = 0; i < size; ++i) { + item = &(ros_message->request.data[i]); + PyObject * pyitem = example_msgs__srv__custom_call__request__convert_to_py(item); + if (!pyitem) { + Py_DECREF(field); + return NULL; + } + int rc = PyList_SetItem(field, i, pyitem); + (void)rc; + assert(rc == 0); + } + assert(PySequence_Check(field)); + // reference is transfered to object + _pymessage->_request = field; + } + { // response + PyObject * field = NULL; + size_t size = ros_message->response.size; + field = PyList_New(size); + if (!field) { + return NULL; + } + example_msgs__srv__CustomCall_Response * item; + for (size_t i = 0; i < size; ++i) { + item = &(ros_message->response.data[i]); + PyObject * pyitem = example_msgs__srv__custom_call__response__convert_to_py(item); + if (!pyitem) { + Py_DECREF(field); + return NULL; + } + int rc = PyList_SetItem(field, i, pyitem); + (void)rc; + assert(rc == 0); + } + assert(PySequence_Check(field)); + // reference is transfered to object + _pymessage->_response = field; + } + + // ownership of _pymessage is transferred to the caller + return (PyObject *)_pymessage; +} diff --git a/rosidl_generator_py/resource/_idl_pkg_decl.h.em b/rosidl_generator_py/resource/_idl_pkg_decl.h.em new file mode 100644 index 00000000..2c5049ab --- /dev/null +++ b/rosidl_generator_py/resource/_idl_pkg_decl.h.em @@ -0,0 +1,179 @@ +// generated from rosidl_generator_py/resource/_idl_pkg_decl.c.em +// generated code does not contain a copyright notice +#pragma once +@ +@####################################################################### +@# EmPy template for generating __decl.h files +@# +@# Context: +@# - package_name (string) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@####################################################################### +@# Handle messages +@####################################################################### +@{ +from rosidl_parser.definition import Message +from rosidl_pycommon import convert_camel_case_to_lower_case_underscore + +include_directives = set() +required_py_modules = [] + +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ + +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=message, include_directives=include_directives, + required_py_modules=required_py_modules) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle services +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ + +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=service.request_message, include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=service.response_message, include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=service.event_message, include_directives=include_directives, + required_py_modules=required_py_modules) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle actions +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ + +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.goal, include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.result, include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.feedback, include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.send_goal_service.request_message, + include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.send_goal_service.response_message, + include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.send_goal_service.event_message, + include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.get_result_service.request_message, + include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.get_result_service.response_message, + include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.get_result_service.event_message, + include_directives=include_directives, + required_py_modules=required_py_modules) +}@ + +@{ +TEMPLATE( + '_msg_decl.h.em', + package_name=package_name, + message=action.feedback_message, include_directives=include_directives, + required_py_modules=required_py_modules) +}@ +@[end for]@ + +#define MAX__IMPORT_INDEX @(len(required_py_modules)) + +typedef struct lazy_import_state +{ + PyObject * cached_imports[MAX__IMPORT_INDEX]; +} lazy_import_state; + +int @(package_name)__lazy_import_initialize(lazy_import_state * state); +int @(package_name)__lazy_import_finalize(lazy_import_state * state); +PyObject * @(package_name)__lazy_import(lazy_import_state * state, size_t index); + +// Since lazy cache global state is shared between multiple typesupport implementations, +// its lifetime should be managed carefully. Extention module can call `__lazy_import` +// function only between `__lazy_import_acquire` and `__lazy_import_release` calls. +// This functions should be removed when cache state becomes module specific. +int @(package_name)__lazy_import_acquire(); +int @(package_name)__lazy_import_release(); diff --git a/rosidl_generator_py/resource/_idl_pkg_import.c.em b/rosidl_generator_py/resource/_idl_pkg_import.c.em new file mode 100644 index 00000000..4d101c61 --- /dev/null +++ b/rosidl_generator_py/resource/_idl_pkg_import.c.em @@ -0,0 +1,204 @@ +// generated from rosidl_generator_py/resource/_idl_pkg_import.c.em +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __import.c files +@# +@# Context: +@# - package_name (string) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@####################################################################### +@# Handle messages +@####################################################################### +@{ +from collections import OrderedDict +from rosidl_parser.definition import Action +from rosidl_parser.definition import Message +from rosidl_parser.definition import Service +from rosidl_pycommon import convert_camel_case_to_lower_case_underscore + + +def collect_py_deps(dst, message: Message): + from rosidl_generator_py.generate_py_impl import SPECIAL_NESTED_BASIC_TYPES + 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 ACTION_GOAL_SERVICE_SUFFIX + from rosidl_parser.definition import ACTION_RESULT_SERVICE_SUFFIX + from rosidl_parser.definition import ACTION_FEEDBACK_MESSAGE_SUFFIX + from rosidl_parser.definition import SERVICE_EVENT_MESSAGE_SUFFIX + from rosidl_parser.definition import SERVICE_REQUEST_MESSAGE_SUFFIX + from rosidl_parser.definition import SERVICE_RESPONSE_MESSAGE_SUFFIX + from rosidl_parser.definition import AbstractNestedType + from rosidl_parser.definition import AbstractSequence + from rosidl_parser.definition import Array + from rosidl_parser.definition import BasicType + from rosidl_parser.definition import NamespacedType + from rosidl_pycommon import convert_camel_case_to_lower_case_underscore + + def cut_service_or_action_suffix(name): + for suffix in ( + SERVICE_EVENT_MESSAGE_SUFFIX, SERVICE_REQUEST_MESSAGE_SUFFIX, SERVICE_RESPONSE_MESSAGE_SUFFIX, + ACTION_GOAL_SERVICE_SUFFIX, ACTION_RESULT_SERVICE_SUFFIX, ACTION_FEEDBACK_MESSAGE_SUFFIX, + ACTION_FEEDBACK_SUFFIX, ACTION_GOAL_SUFFIX, ACTION_RESULT_SUFFIX, + ): + if name.endswith(suffix): + name = name[:-len(suffix)] + return name + + for member in message.structure.members: + if isinstance(member.type, AbstractNestedType) and isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES: + if isinstance(member.type, Array): + if 'numpy.ndarray' not in dst: + dst['numpy.ndarray'] = ('numpy', 'ndarray', False) + dtype = SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype'] + if dtype not in dst: + module, name = dtype.rsplit('.', maxsplit=1) + dst[dtype] = (module, name, False) + elif isinstance(member.type, AbstractSequence) and 'array.array' not in dst: + dst['array.array'] = ('array', 'array', False) + + interface_name = cut_service_or_action_suffix(message.structure.namespaced_type.name) + module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_name) + full_module_name = ".".join((*message.structure.namespaced_type.namespaces, module_name)) + object_name = message.structure.namespaced_type.name + type_name = ".".join(message.structure.namespaced_type.namespaced_name()) + + assert type_name not in dst + # For example_msgs.srv.MyService_Request from example_msgs/srv/MyService.srv added + # ["example_msgs.srv.MyService_Request"] = ("example_msgs.msg._my_service", "MyService_Request", True) + dst[type_name] = (full_module_name, object_name, True) + + +required_py_objects = OrderedDict() + +for message in content.get_elements_of_type(Message): + collect_py_deps(required_py_objects, message) + +for service in content.get_elements_of_type(Service): + collect_py_deps(required_py_objects, service.request_message) + collect_py_deps(required_py_objects, service.response_message) + collect_py_deps(required_py_objects, service.event_message) + +for action in content.get_elements_of_type(Action): + collect_py_deps(required_py_objects, action.goal) + collect_py_deps(required_py_objects, action.result) + collect_py_deps(required_py_objects, action.feedback) + collect_py_deps(required_py_objects, action.send_goal_service.request_message) + collect_py_deps(required_py_objects, action.send_goal_service.response_message) + collect_py_deps(required_py_objects, action.send_goal_service.event_message) + collect_py_deps(required_py_objects, action.get_result_service.request_message) + collect_py_deps(required_py_objects, action.get_result_service.response_message) + collect_py_deps(required_py_objects, action.get_result_service.event_message) + collect_py_deps(required_py_objects, action.feedback_message) + +}@ +#include +#include +#include "./_@(package_name)_decl.h" + + +typedef struct +{ + const char * module_name; + const char * object_name; + bool ensure_is_type; +} lazy_import_info; + + +static lazy_import_info import_infos[MAX__IMPORT_INDEX] = { +@[for type_name, (module_name, object_name, ensure) in required_py_objects.items()]@ +@{ parts = type_name.split('.')}@ +@{ const_name = '__'.join(parts[:-1] + [convert_camel_case_to_lower_case_underscore(parts[-1])]).upper()}@ +@{ ensure_is_type = "true" if ensure else "false"}@ + // @(type_name) + [@(const_name)__IMPORT_INDEX] = {"@(module_name)", "@(object_name)", @(ensure_is_type)}, +@[end for]@ +}; + +int @(package_name)__lazy_import_initialize(lazy_import_state * state) +{ + assert(state != NULL); + for (size_t i = 0; i < MAX__IMPORT_INDEX; ++i) { + state->cached_imports[i] = NULL; + } + return 0; +} + +int @(package_name)__lazy_import_finalize(lazy_import_state * state) +{ + assert(state != NULL); + for (size_t i = 0; i < MAX__IMPORT_INDEX; ++i) { + Py_CLEAR(state->cached_imports[i]); + } + return 0; +} + + +static PyObject * state_storage = NULL; + +PyObject * @(package_name)__lazy_import(lazy_import_state * state, size_t index) +{ + if (state == NULL) { + if (state_storage == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Internal error. Module not initilized properly"); + return NULL; + } + state = (lazy_import_state *)PyCapsule_GetPointer(state_storage, NULL); + if (state == NULL) { + return NULL; + } + } + + assert(index < MAX__IMPORT_INDEX); + PyObject * py_type = state->cached_imports[index]; + if (py_type != NULL) { + return py_type; + } + + const lazy_import_info * info = &import_infos[index]; + PyObject * module = PyImport_ImportModule(info->module_name); + if (!module) { + return NULL; + } + py_type = PyObject_GetAttrString(module, info->object_name); + Py_DECREF(module); + if (!py_type) { + return NULL; + } + if (info->ensure_is_type && !PyType_Check(py_type)) { + PyErr_SetString(PyExc_RuntimeError, "Imported object is not a python type"); + return NULL; + } + + state->cached_imports[index] = py_type; + return py_type; +} + +static void clear_storage(PyObject * capsule) +{ + (void)capsule; + state_storage = NULL; +} + +int @(package_name)__lazy_import_acquire() +{ + if (state_storage == NULL) { + lazy_import_state * state = PyMem_Malloc(sizeof(lazy_import_state)); + if (@(package_name)__lazy_import_initialize(state) != 0) { + return 1; + } + state_storage = PyCapsule_New(state, NULL, clear_storage); + } else { + Py_INCREF(state_storage); + } + return 0; +} + +int @(package_name)__lazy_import_release() +{ + Py_DECREF(state_storage); + 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 0a73dd2d..f715dd40 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 @@ -21,22 +21,6 @@ include_directives = set() register_functions = [] }@ #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)]@ @@ -85,6 +69,40 @@ TEMPLATE( }@ @[end for]@ +#include "./_@(package_name)_decl.h" + +static PyMethodDef @(package_name)__methods[] = { + {NULL, NULL, 0, NULL} /* sentinel */ +}; + +static int +_@(package_name)_clear(PyObject * module) +{ + (void)module; + @(package_name)__lazy_import_release(); + return 0; +} + +static void +_@(package_name)_free(void * module) +{ + _@(package_name)_clear((PyObject *)module); +} + + +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, + _@(package_name)_clear, + _@(package_name)_free, +}; + + PyMODINIT_FUNC PyInit_@(package_name)_s__@(typesupport_impl)(void) { @@ -103,5 +121,6 @@ PyInit_@(package_name)_s__@(typesupport_impl)(void) } @[end for]@ + @(package_name)__lazy_import_acquire(); return pymodule; } diff --git a/rosidl_generator_py/resource/_idl_support.c.em b/rosidl_generator_py/resource/_idl_support.c.em index 3159c584..7774c9c6 100644 --- a/rosidl_generator_py/resource/_idl_support.c.em +++ b/rosidl_generator_py/resource/_idl_support.c.em @@ -18,7 +18,6 @@ from rosidl_parser.definition import Message include_directives = set() -lazy_import_methods = set() }@ @[for message in content.get_elements_of_type(Message)]@ @@ -27,8 +26,7 @@ lazy_import_methods = set() TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=message, include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + message=message, include_directives=include_directives) }@ @[end for]@ @ @@ -44,24 +42,21 @@ from rosidl_parser.definition import Service TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=service.request_message, include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + 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, - lazy_import_methods=lazy_import_methods) + message=service.response_message, include_directives=include_directives) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=service.event_message, include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + message=service.event_message, include_directives=include_directives) }@ @[end for]@ @ @@ -77,24 +72,21 @@ from rosidl_parser.definition import Action TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.goal, include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + message=action.goal, include_directives=include_directives) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.result, include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + message=action.result, include_directives=include_directives) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.feedback, include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + message=action.feedback, include_directives=include_directives) }@ @{ @@ -102,8 +94,7 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.send_goal_service.request_message, - include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + include_directives=include_directives) }@ @{ @@ -111,8 +102,7 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.send_goal_service.response_message, - include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + include_directives=include_directives) }@ @{ @@ -120,8 +110,7 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.send_goal_service.event_message, - include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + include_directives=include_directives) }@ @{ @@ -129,8 +118,7 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.get_result_service.request_message, - include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + include_directives=include_directives) }@ @{ @@ -138,8 +126,7 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.get_result_service.response_message, - include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + include_directives=include_directives) }@ @{ @@ -147,15 +134,13 @@ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, message=action.get_result_service.event_message, - include_directives=include_directives, - lazy_import_methods=lazy_import_methods) + 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, - lazy_import_methods=lazy_import_methods) + message=action.feedback_message, include_directives=include_directives) }@ @[end for]@ diff --git a/rosidl_generator_py/resource/_import_type.c.em b/rosidl_generator_py/resource/_import_type.c.em deleted file mode 100644 index e773f978..00000000 --- a/rosidl_generator_py/resource/_import_type.c.em +++ /dev/null @@ -1,32 +0,0 @@ -@{ -module_name, type_name = full_type_name.rsplit(".", maxsplit=1) -ensure_is_type = locals().get('ensure_is_type', False) -}@ -@ -static PyObject * @(func_name)() -{ - // TODO(almaslov) proper deinitialization - static PyObject * py_type = NULL; - if (py_type != NULL) { - return py_type; - } - - PyObject * module = PyImport_ImportModule("@(module_name)"); - if (!module) { - return NULL; - } - py_type = PyObject_GetAttrString(module, "@(type_name)"); - Py_DECREF(module); - if (!py_type) { - return NULL; - } -@[if ensure_is_type]@ - if (!PyType_Check(py_type)) { - PyErr_SetString(PyExc_RuntimeError, "@(type_name) is not a python type"); - return NULL; - } -@[end if]@ - - return py_type; -} - diff --git a/rosidl_generator_py/resource/_msg_base.c.em b/rosidl_generator_py/resource/_msg_base.c.em index c3dd9f0c..04dc6bdd 100644 --- a/rosidl_generator_py/resource/_msg_base.c.em +++ b/rosidl_generator_py/resource/_msg_base.c.em @@ -49,7 +49,8 @@ def primitive_msg_type_to_pymember_type(type_): header_files = [ 'Python.h', 'stdbool.h', - 'structmember.h' + 'structmember.h', + './_%s_decl.h' % package_name ] }@ @[for header_file in header_files]@ @@ -70,26 +71,6 @@ repeated_header_file = header_file in include_directives @[end for]@ -typedef struct -{ - PyObject_HEAD - /* Type-specific fields go here. */ -@[for member in message.structure.members]@ -@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ -@[ continue]@ -@[ end if]@ -@[ if isinstance(member.type, BasicType)]@ -@[ if member.type.typename == 'float']@ - double _@(member.name); -@[ else]@ - @(primitive_msg_type_to_c(member.type)) _@(member.name); -@[ end if]@ -@[ else isinstance(member.type, AbstractGenericString)]@ - PyObject * _@(member.name); -@[ end if]@ -@[end for]@ -} @(message.structure.namespaced_type.name)Base; - static struct PyMemberDef @(message.structure.namespaced_type.name)Base_members[] = { @[for member in message.structure.members]@ @[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ diff --git a/rosidl_generator_py/resource/_msg_decl.h.em b/rosidl_generator_py/resource/_msg_decl.h.em new file mode 100644 index 00000000..1cddeaff --- /dev/null +++ b/rosidl_generator_py/resource/_msg_decl.h.em @@ -0,0 +1,116 @@ +@# Included from rosidl_generator_py/resource/_idl_pkg_decl.h.em +@{ +from rosidl_generator_py.generate_py_impl import SPECIAL_NESTED_BASIC_TYPES +from rosidl_parser.definition import AbstractNestedType +from rosidl_parser.definition import AbstractSequence +from rosidl_parser.definition import AbstractString +from rosidl_parser.definition import AbstractWString +from rosidl_parser.definition import Array +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME +from rosidl_parser.definition import NamespacedType +from rosidl_pycommon import convert_camel_case_to_lower_case_underscore + + +def primitive_msg_type_to_c(type_): + from rosidl_generator_c import BASIC_IDL_TYPES_TO_C + from rosidl_parser.definition import AbstractString + from rosidl_parser.definition import AbstractWString + from rosidl_parser.definition import BasicType + if isinstance(type_, AbstractString): + return 'rosidl_runtime_c__String' + if isinstance(type_, AbstractWString): + return 'rosidl_runtime_c__U16String' + assert isinstance(type_, BasicType) + return BASIC_IDL_TYPES_TO_C[type_.typename] + + +header_files = [ + 'Python.h', + 'stdbool.h', + 'structmember.h' +] +}@ +@[for header_file in header_files]@ +@{ +repeated_header_file = header_file in include_directives +}@ +@[ if repeated_header_file]@ +// 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]@ + + +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ +@[for member in message.structure.members]@ +@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ +@[ continue]@ +@[ end if]@ +@[ if isinstance(member.type, BasicType)]@ +@[ if member.type.typename == 'float']@ + double _@(member.name); +@[ else]@ + @(primitive_msg_type_to_c(member.type)) _@(member.name); +@[ end if]@ +@[ else isinstance(member.type, AbstractGenericString)]@ + PyObject * _@(member.name); +@[ end if]@ +@[end for]@ +} @(message.structure.namespaced_type.name)Base; + +// Import-support constants for @(message.structure.namespaced_type.name)Base type +@{ +locally_declared = set() +}@ +@[for member in message.structure.members]@ +@[ if isinstance(member.type, AbstractNestedType) and isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES]@ +@[ if isinstance(member.type, Array)]@ +@[ if 'numpy.ndarray' not in required_py_modules]@ +#define NUMPY__NDARRAY__IMPORT_INDEX @(len(required_py_modules)) +@{ required_py_modules.append('numpy.ndarray')}@ +@[ elif 'numpy.ndarray' not in locally_declared]@ +// NUMPY__NDARRAY__IMPORT_INDEX defined above +@[ end if]@ +@{ locally_declared.add('numpy.ndarray')}@ +@{ dtype = SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype']}@ +@{ const_name = dtype.replace('.', '__').upper()}@ +@[ if dtype not in required_py_modules]@ +#define @(const_name)__IMPORT_INDEX @(len(required_py_modules)) +@{ required_py_modules.append(dtype)}@ +@[ elif dtype not in locally_declared]@ +// @(const_name)__IMPORT_INDEX defined above +@[ end if]@ +@{ locally_declared.add(dtype)}@ +@[ elif isinstance(member.type, AbstractSequence)]@ +@[ if 'array.array' not in required_py_modules]@ +#define ARRAY__ARRAY__IMPORT_INDEX @(len(required_py_modules)) +@{ required_py_modules.append('array.array')}@ +@[ elif 'array.array' not in locally_declared]@ +// ARRAY__ARRAY__IMPORT_INDEX defined above +@[ end if]@ +@{ locally_declared.add('array.array')}@ +@[ end if]@ +@[ end if]@ +@[end for]@ +@ +@{ +type_ = message.structure.namespaced_type +const_name = '__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]).upper() +# const_name = '__'.join(type_.namespaced_name()).upper() +assert const_name not in required_py_modules, "Const name collision" +const_value = len(required_py_modules) +required_py_modules.append(const_name) +}@ +#define @(const_name)__IMPORT_INDEX @(const_value) + diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index b0e39b78..70360982 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -39,6 +39,7 @@ header_files = [ 'rosidl_runtime_c/visibility_control.h', include_base + '__struct.h', include_base + '__functions.h', + '../_%s_decl.h' % package_name, ] }@ @[for header_file in header_files]@ @@ -156,58 +157,17 @@ PyObject * @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_unde @[ end if]@ @[end for]@ -@# TODO(aamaslov) duplicated struct definition here -typedef struct -{ - PyObject_HEAD - /* Type-specific fields go here. */ -@[for member in message.structure.members]@ -@[ if len(message.structure.members) == 1 and member.name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME]@ -@[ continue]@ -@[ end if]@ -@[ if isinstance(member.type, BasicType)]@ -@[ if member.type.typename == 'float']@ - double _@(member.name); -@[ else]@ - @(primitive_msg_type_to_c(member.type)) _@(member.name); -@[ end if]@ -@[ else isinstance(member.type, AbstractGenericString)]@ - PyObject * _@(member.name); -@[ end if]@ -@[end for]@ -} @(message.structure.namespaced_type.name)Base; - @{ -for member in message.structure.members: - if isinstance(member.type, AbstractNestedType) and isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES: - if isinstance(member.type, Array): - if 'numpy.ndarray' not in lazy_import_methods: - lazy_import_methods.add('numpy.ndarray') - TEMPLATE('_import_type.c.em', full_type_name='numpy.ndarray', func_name='lazy_import_ndarray') - dtype = SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype'] - if dtype not in lazy_import_methods: - lazy_import_methods.add(dtype) - TEMPLATE('_import_type.c.em', full_type_name=dtype, func_name='lazy_import_numpy_' + member.type.value_type.typename) - elif isinstance(member.type, AbstractSequence) and 'array.array' not in lazy_import_methods: - lazy_import_methods.add('array.array') - TEMPLATE('_import_type.c.em', full_type_name='array.array', func_name='lazy_import_array') - module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_path.stem) -class_module = '%s.%s' % ('.'.join(message.structure.namespaced_type.namespaces), module_name) -namespaced_type = message.structure.namespaced_type.name -full_type_name = '.'.join(message.structure.namespaced_type.namespaces + [module_name, message.structure.namespaced_type.name]) -import_func_name = 'lazy_import_' + convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name) +import_index = '__'.join(message.structure.namespaced_type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name)]).upper() no_fields = len(message.structure.members) == 1 and message.structure.members[0].name == EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME -TEMPLATE( - '_import_type.c.em', - full_type_name=full_type_name, func_name=import_func_name, ensure_is_type=True) }@ ROSIDL_GENERATOR_C_EXPORT bool @('__'.join(message.structure.namespaced_type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.namespaced_type.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message) { // check that the passed message is of the expected Python class { - PyTypeObject * py_type = (PyTypeObject *)@(import_func_name)(); + PyTypeObject * py_type = (PyTypeObject *)@(package_name)__lazy_import(NULL, @(import_index)__IMPORT_INDEX); assert(Py_TYPE(_pymsg) == py_type); } @(msg_typename) * ros_message = _ros_message; @@ -489,12 +449,10 @@ PyObject * @('__'.join(message.structure.namespaced_type.namespaces + [convert_c /* NOTE(esteve): Call constructor of @(message.structure.namespaced_type.name) */ @(message.structure.namespaced_type.name)Base * _pymessage = NULL; { - PyObject * py_type = @(import_func_name)(); - if (!py_type) { + PyTypeObject * type = (PyTypeObject *)@(package_name)__lazy_import(NULL, @(import_index)__IMPORT_INDEX); + if (!type) { return NULL; } - - PyTypeObject * type = (PyTypeObject *)py_type; assert(type->tp_new); PyObject * empty_tuple = PyTuple_New(0); @@ -528,11 +486,12 @@ if isinstance(type_, AbstractNestedType): @[ end if]@ @[ if isinstance(member.type, AbstractNestedType) and isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES]@ @[ if isinstance(member.type, Array)]@ - PyObject * array_type = lazy_import_ndarray(); +@{ dtype = SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype']} + PyObject * array_type = @(package_name)__lazy_import(NULL, NUMPY__NDARRAY__IMPORT_INDEX); if (!array_type) { return NULL; } - PyObject * element_type = lazy_import_numpy_@(member.type.value_type.typename)(); + PyObject * element_type = @(package_name)__lazy_import(NULL, @(dtype.replace('.', '__').upper())__IMPORT_INDEX); if (!element_type) { return NULL; } @@ -549,7 +508,7 @@ if isinstance(type_, AbstractNestedType): memcpy(dst, src, @(member.type.size) * sizeof(@primitive_msg_type_to_c(member.type.value_type))); @[ elif isinstance(member.type, AbstractSequence)]@ { - PyObject * array_type = lazy_import_array(); + PyObject * array_type = @(package_name)__lazy_import(NULL, ARRAY__ARRAY__IMPORT_INDEX); if (!array_type) { return NULL; } 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 2a784c38..3cd99e57 100644 --- a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py +++ b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py @@ -192,17 +192,22 @@ def print_warning_if_reserved_keyword(member_name, interface_type, interface_nam minimum_timestamp=latest_target_timestamp) generated_files.append(generated_file) - # expand base classes module template - template_file = os.path.join(template_dir, '_idl_pkg_bases.c.em') - generated_base_file = os.path.join(args['output_dir'], '_%s_bases.c' % package_name) - data = { - 'package_name': args['package_name'], - 'content': idl_content, - } - expand_template( - template_file, data, generated_base_file, - minimum_timestamp=latest_target_timestamp) - generated_files.append(generated_file) + # expand templates which are common for all typesupport implementation + for template_file, output_file in ( + ('_idl_pkg_bases.c.em', '_%s_bases.c' % package_name), + ('_idl_pkg_import.c.em', '_%s_import.c' % package_name), + ('_idl_pkg_decl.h.em', '_%s_decl.h' % package_name), + ): + template_file = os.path.join(template_dir, template_file) + generated_base_file = os.path.join(args['output_dir'], output_file) + data = { + 'package_name': args['package_name'], + 'content': idl_content, + } + expand_template( + template_file, data, generated_base_file, + minimum_timestamp=latest_target_timestamp) + generated_files.append(generated_file) return generated_files From e66f2af377ddb806051c0d6e2cd7b03e364c1d35 Mon Sep 17 00:00:00 2001 From: EsipovPA Date: Sun, 7 Jul 2024 02:17:14 +0300 Subject: [PATCH 6/7] Rebase fixes. Fix library lincage and include_dirs for bases lib. Add '_check_fields' as a default value in a __slots__ list for generated messages. Signed-off-by: EsipovPA --- ...rosidl_generator_py_generate_interfaces.cmake | 16 ++++++++++++---- rosidl_generator_py/resource/_msg.py.em | 2 +- 2 files changed, 13 insertions(+), 5 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 4912f16b..afe36883 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -191,14 +191,23 @@ endif() rosidl_get_typesupport_target(c_typesupport_target "${rosidl_generate_interfaces_TARGET}" "rosidl_typesupport_c") target_link_libraries(${_target_name_lib} PRIVATE ${c_typesupport_target}) - set(_target_name_bases_lib "${rosidl_generate_interfaces_TARGET}__bases") add_library(${_target_name_bases_lib} SHARED ${_generated_c_base_files}) add_dependencies( ${_target_name_bases_lib} ${rosidl_generate_interfaces_TARGET}${_target_suffix}) -target_link_libraries(${_target_name_bases_lib} ${PythonExtra_LIBRARIES}) -target_include_directories(${_target_name_bases_lib} PRIVATE ${PythonExtra_INCLUDE_DIRS}) +target_link_libraries( + ${_target_name_bases_lib} + Python3::NumPy + Python3::Python + ${PythonExtra_LIBRARIES} +) +target_include_directories( + ${_target_name_bases_lib} PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c + ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py + ${PythonExtra_INCLUDE_DIRS} +) set_target_properties(${_target_name_bases_lib} PROPERTIES COMPILE_OPTIONS "${_extension_compile_flags}" @@ -206,7 +215,6 @@ set_target_properties(${_target_name_bases_lib} PROPERTIES LIBRARY_OUTPUT_DIRECTORY${_build_type} ${_output_path} RUNTIME_OUTPUT_DIRECTORY${_build_type} ${_output_path} OUTPUT_NAME "_${PROJECT_NAME}_bases${PythonExtra_EXTENSION_SUFFIX}" - SUFFIX "${PythonExtra_EXTENSION_EXTENSION}" ) if(NOT rosidl_generate_interfaces_SKIP_INSTALL) install(TARGETS ${_target_name_bases_lib} diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index f02861f2..f3c643bb 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -230,7 +230,7 @@ class @(message.structure.namespaced_type.name)(_bases.@(message.structure.names # This field is modified after class creation. # See the comment to Metaclass_@(message.structure.namespaced_type.name).__new__ - __slots__ = [] + __slots__ = ['_check_fields'] _fields_and_field_types = { @[for member in message.structure.members]@ From 9d9260368cb53d3202cf23597027da38264caf7f Mon Sep 17 00:00:00 2001 From: EsipovPA Date: Mon, 12 Aug 2024 22:42:02 +0300 Subject: [PATCH 7/7] Fix linter tests. Remove example messages Signed-off-by: EsipovPA --- .../example/_example_msgs_bases.c | 247 ------- .../example/_example_msgs_decl.h | 101 --- .../example/_example_msgs_import.c | 116 --- .../_example_msgs_s.ep.rosidl_typesupport_c.c | 666 ------------------ .../example/msg/CustomMessage.msg | 5 - rosidl_generator_py/example/msg/__init__.py | 1 - .../example/msg/_custom_message.py | 291 -------- .../example/msg/_custom_message_s.c | 386 ---------- .../example/srv/CustomCall.srv | 3 - rosidl_generator_py/example/srv/__init__.py | 4 - .../example/srv/_custom_call.py | 546 -------------- .../example/srv/_custom_call_s.c | 332 --------- 12 files changed, 2698 deletions(-) delete mode 100644 rosidl_generator_py/example/_example_msgs_bases.c delete mode 100644 rosidl_generator_py/example/_example_msgs_decl.h delete mode 100644 rosidl_generator_py/example/_example_msgs_import.c delete mode 100644 rosidl_generator_py/example/_example_msgs_s.ep.rosidl_typesupport_c.c delete mode 100644 rosidl_generator_py/example/msg/CustomMessage.msg delete mode 100644 rosidl_generator_py/example/msg/__init__.py delete mode 100644 rosidl_generator_py/example/msg/_custom_message.py delete mode 100644 rosidl_generator_py/example/msg/_custom_message_s.c delete mode 100644 rosidl_generator_py/example/srv/CustomCall.srv delete mode 100644 rosidl_generator_py/example/srv/__init__.py delete mode 100644 rosidl_generator_py/example/srv/_custom_call.py delete mode 100644 rosidl_generator_py/example/srv/_custom_call_s.c diff --git a/rosidl_generator_py/example/_example_msgs_bases.c b/rosidl_generator_py/example/_example_msgs_bases.c deleted file mode 100644 index 76ba4a8e..00000000 --- a/rosidl_generator_py/example/_example_msgs_bases.c +++ /dev/null @@ -1,247 +0,0 @@ -// generated from rosidl_generator_py/resource/_idl_pkg_bases.c.em -// generated code does not contain a copyright notice -#include -#include -#include -#include "./_example_msgs_decl.h" - - -static struct PyMemberDef CustomMessageBase_members[] = { - {"_x", T_USHORT, offsetof(CustomMessageBase, _x), 0, NULL}, - {"_ts", T_OBJECT, offsetof(CustomMessageBase, _ts), 0, NULL}, - {"_fixed_seq", T_OBJECT, offsetof(CustomMessageBase, _fixed_seq), 0, NULL}, - {"_limited_seq", T_OBJECT, offsetof(CustomMessageBase, _limited_seq), 0, NULL}, - {"_unlimited_seq", T_OBJECT, offsetof(CustomMessageBase, _unlimited_seq), 0, NULL}, - {NULL} /* Sentinel */ -}; - -static void CustomMessageBase_dealloc(CustomMessageBase * self) -{ - Py_XDECREF(self->_ts); - Py_XDECREF(self->_fixed_seq); - Py_XDECREF(self->_limited_seq); - Py_XDECREF(self->_unlimited_seq); - Py_TYPE(self)->tp_free((PyObject *)self); -} - - -static PyTypeObject CustomMessageBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "CustomMessageBase", - .tp_doc = "Base for CustomMessage python class", - .tp_basicsize = sizeof(CustomMessageBase), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_new = PyType_GenericNew, - .tp_dealloc = (destructor)CustomMessageBase_dealloc, - .tp_members = CustomMessageBase_members, -}; - - -static int8_t _register_base_msg_type__msg__custom_message(PyObject * module) -{ - if (PyType_Ready(&CustomMessageBaseType) < 0) { - return 1; - } - - Py_INCREF(&CustomMessageBaseType); - if (PyModule_AddObject(module, "CustomMessageBase", (PyObject *) &CustomMessageBaseType) < 0) { - Py_DECREF(&CustomMessageBaseType); - return 1; - } - return 0; -} -// already included above -// #include -// already included above -// #include -// already included above -// #include -// already included above -// #include "./_example_msgs_decl.h" - - -static struct PyMemberDef CustomCall_RequestBase_members[] = { - {"_my_param", T_INT, offsetof(CustomCall_RequestBase, _my_param), 0, NULL}, - {NULL} /* Sentinel */ -}; - -static void CustomCall_RequestBase_dealloc(CustomCall_RequestBase * self) -{ - Py_TYPE(self)->tp_free((PyObject *)self); -} - - -static PyTypeObject CustomCall_RequestBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "CustomCall_RequestBase", - .tp_doc = "Base for CustomCall_Request python class", - .tp_basicsize = sizeof(CustomCall_RequestBase), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_new = PyType_GenericNew, - .tp_dealloc = (destructor)CustomCall_RequestBase_dealloc, - .tp_members = CustomCall_RequestBase_members, -}; - - -static int8_t _register_base_msg_type__srv__custom_call__request(PyObject * module) -{ - if (PyType_Ready(&CustomCall_RequestBaseType) < 0) { - return 1; - } - - Py_INCREF(&CustomCall_RequestBaseType); - if (PyModule_AddObject(module, "CustomCall_RequestBase", (PyObject *) &CustomCall_RequestBaseType) < 0) { - Py_DECREF(&CustomCall_RequestBaseType); - return 1; - } - return 0; -} - -// already included above -// #include -// already included above -// #include -// already included above -// #include -// already included above -// #include "./_example_msgs_decl.h" - - -static struct PyMemberDef CustomCall_ResponseBase_members[] = { - {"_my_result", T_INT, offsetof(CustomCall_ResponseBase, _my_result), 0, NULL}, - {NULL} /* Sentinel */ -}; - -static void CustomCall_ResponseBase_dealloc(CustomCall_ResponseBase * self) -{ - Py_TYPE(self)->tp_free((PyObject *)self); -} - - -static PyTypeObject CustomCall_ResponseBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "CustomCall_ResponseBase", - .tp_doc = "Base for CustomCall_Response python class", - .tp_basicsize = sizeof(CustomCall_ResponseBase), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_new = PyType_GenericNew, - .tp_dealloc = (destructor)CustomCall_ResponseBase_dealloc, - .tp_members = CustomCall_ResponseBase_members, -}; - - -static int8_t _register_base_msg_type__srv__custom_call__response(PyObject * module) -{ - if (PyType_Ready(&CustomCall_ResponseBaseType) < 0) { - return 1; - } - - Py_INCREF(&CustomCall_ResponseBaseType); - if (PyModule_AddObject(module, "CustomCall_ResponseBase", (PyObject *) &CustomCall_ResponseBaseType) < 0) { - Py_DECREF(&CustomCall_ResponseBaseType); - return 1; - } - return 0; -} - -// already included above -// #include -// already included above -// #include -// already included above -// #include -// already included above -// #include "./_example_msgs_decl.h" - - -static struct PyMemberDef CustomCall_EventBase_members[] = { - {"_info", T_OBJECT, offsetof(CustomCall_EventBase, _info), 0, NULL}, - {"_request", T_OBJECT, offsetof(CustomCall_EventBase, _request), 0, NULL}, - {"_response", T_OBJECT, offsetof(CustomCall_EventBase, _response), 0, NULL}, - {NULL} /* Sentinel */ -}; - -static void CustomCall_EventBase_dealloc(CustomCall_EventBase * self) -{ - Py_XDECREF(self->_info); - Py_XDECREF(self->_request); - Py_XDECREF(self->_response); - Py_TYPE(self)->tp_free((PyObject *)self); -} - - -static PyTypeObject CustomCall_EventBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "CustomCall_EventBase", - .tp_doc = "Base for CustomCall_Event python class", - .tp_basicsize = sizeof(CustomCall_EventBase), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_new = PyType_GenericNew, - .tp_dealloc = (destructor)CustomCall_EventBase_dealloc, - .tp_members = CustomCall_EventBase_members, -}; - - -static int8_t _register_base_msg_type__srv__custom_call__event(PyObject * module) -{ - if (PyType_Ready(&CustomCall_EventBaseType) < 0) { - return 1; - } - - Py_INCREF(&CustomCall_EventBaseType); - if (PyModule_AddObject(module, "CustomCall_EventBase", (PyObject *) &CustomCall_EventBaseType) < 0) { - Py_DECREF(&CustomCall_EventBaseType); - return 1; - } - return 0; -} - - -static PyModuleDef _module = { - PyModuleDef_HEAD_INIT, - .m_name = "_example_msgs_bases", - .m_doc = "Extention module for example_msgs messages", - .m_size = -1, -}; - - -PyMODINIT_FUNC -PyInit__example_msgs_bases(void) -{ - PyObject * pymodule = NULL; - pymodule = PyModule_Create(&_module); - if (!pymodule) { - return NULL; - } - int8_t err; - - err = _register_base_msg_type__msg__custom_message(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_base_msg_type__srv__custom_call__request(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_base_msg_type__srv__custom_call__response(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_base_msg_type__srv__custom_call__event(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - return pymodule; -} diff --git a/rosidl_generator_py/example/_example_msgs_decl.h b/rosidl_generator_py/example/_example_msgs_decl.h deleted file mode 100644 index 1c606479..00000000 --- a/rosidl_generator_py/example/_example_msgs_decl.h +++ /dev/null @@ -1,101 +0,0 @@ -// generated from rosidl_generator_py/resource/_idl_pkg_decl.c.em -// generated code does not contain a copyright notice -#pragma once -#include -#include -#include - - -typedef struct -{ - PyObject_HEAD - /* Type-specific fields go here. */ - uint16_t _x; - PyObject * _ts; - PyObject * _fixed_seq; - PyObject * _limited_seq; - PyObject * _unlimited_seq; -} CustomMessageBase; - -// Import support constants for CustomMessageBase type -#define NUMPY__NDARRAY__IMPORT_INDEX 0 -#define NUMPY__INT16__IMPORT_INDEX 1 -#define ARRAY__ARRAY__IMPORT_INDEX 2 -#define EXAMPLE_MSGS__MSG__CUSTOM_MESSAGE__IMPORT_INDEX 3 - -// already included above -// #include -// already included above -// #include -// already included above -// #include - - -typedef struct -{ - PyObject_HEAD - /* Type-specific fields go here. */ - int32_t _my_param; -} CustomCall_RequestBase; - -// Import support constants for CustomCall_RequestBase type -#define EXAMPLE_MSGS__SRV__CUSTOM_CALL__REQUEST__IMPORT_INDEX 4 - - -// already included above -// #include -// already included above -// #include -// already included above -// #include - - -typedef struct -{ - PyObject_HEAD - /* Type-specific fields go here. */ - int32_t _my_result; -} CustomCall_ResponseBase; - -// Import support constants for CustomCall_ResponseBase type -#define EXAMPLE_MSGS__SRV__CUSTOM_CALL__RESPONSE__IMPORT_INDEX 5 - - -// already included above -// #include -// already included above -// #include -// already included above -// #include - - -typedef struct -{ - PyObject_HEAD - /* Type-specific fields go here. */ - PyObject * _info; - PyObject * _request; - PyObject * _response; -} CustomCall_EventBase; - -// Import support constants for CustomCall_EventBase type -#define EXAMPLE_MSGS__SRV__CUSTOM_CALL__EVENT__IMPORT_INDEX 6 - - -#define MAX__IMPORT_INDEX 7 - -typedef struct lazy_import_state -{ - PyObject * cached_imports[MAX__IMPORT_INDEX]; -} lazy_import_state; - -int example_msgs__lazy_import_initialize(lazy_import_state * state); -int example_msgs__lazy_import_finalize(lazy_import_state * state); -PyObject * example_msgs__lazy_import(lazy_import_state * state, size_t index); - -// Since lazy cache global state is shared between multiple typesupport implementations, -// its lifetime should be managed carefully. Extention module can call `__lazy_import` -// function only between `__lazy_import_acquire` and `__lazy_import_release` calls. -// This functions should be removed when cache state becomes module specific. -int example_msgs__lazy_import_acquire(); -int example_msgs__lazy_import_release(); diff --git a/rosidl_generator_py/example/_example_msgs_import.c b/rosidl_generator_py/example/_example_msgs_import.c deleted file mode 100644 index cc00290e..00000000 --- a/rosidl_generator_py/example/_example_msgs_import.c +++ /dev/null @@ -1,116 +0,0 @@ -// generated from rosidl_generator_py/resource/_idl_pkg_import.c.em -// generated code does not contain a copyright notice -#include -#include -#include "./_example_msgs_decl.h" - - -typedef struct -{ - const char * module_name; - const char * object_name; - bool ensure_is_type; -} lazy_import_info; - - -static lazy_import_info import_infos[MAX__IMPORT_INDEX] = { - // numpy.ndarray - [NUMPY__NDARRAY__IMPORT_INDEX] = {"numpy", "ndarray", false}, - // numpy.int16 - [NUMPY__INT16__IMPORT_INDEX] = {"numpy", "int16", false}, - // array.array - [ARRAY__ARRAY__IMPORT_INDEX] = {"array", "array", false}, - // example_msgs.msg.CustomMessage - [EXAMPLE_MSGS__MSG__CUSTOM_MESSAGE__IMPORT_INDEX] = {"example_msgs.msg._custom_message", "CustomMessage", true}, - // example_msgs.srv.CustomCall_Request - [EXAMPLE_MSGS__SRV__CUSTOM_CALL__REQUEST__IMPORT_INDEX] = {"example_msgs.srv._custom_call", "CustomCall_Request", true}, - // example_msgs.srv.CustomCall_Response - [EXAMPLE_MSGS__SRV__CUSTOM_CALL__RESPONSE__IMPORT_INDEX] = {"example_msgs.srv._custom_call", "CustomCall_Response", true}, - // example_msgs.srv.CustomCall_Event - [EXAMPLE_MSGS__SRV__CUSTOM_CALL__EVENT__IMPORT_INDEX] = {"example_msgs.srv._custom_call", "CustomCall_Event", true}, -}; - -int example_msgs__lazy_import_initialize(lazy_import_state * state) -{ - assert(state != NULL); - for (size_t i = 0; i < MAX__IMPORT_INDEX; ++i) { - state->cached_imports[i] = NULL; - } - return 0; -} - -int example_msgs__lazy_import_finalize(lazy_import_state * state) -{ - assert(state != NULL); - for (size_t i = 0; i < MAX__IMPORT_INDEX; ++i) { - Py_CLEAR(state->cached_imports[i]); - } - return 0; -} - - -static PyObject * state_storage = NULL; - -PyObject * example_msgs__lazy_import(lazy_import_state * state, size_t index) -{ - if (state == NULL) { - if (state_storage == NULL) { - PyErr_SetString(PyExc_RuntimeError, "Internal error. Module not initilized properly"); - return NULL; - } - state = (lazy_import_state *)PyCapsule_GetPointer(state_storage, NULL); - if (state == NULL) { - return NULL; - } - } - - assert(index < MAX__IMPORT_INDEX); - PyObject * py_type = state->cached_imports[index]; - if (py_type != NULL) { - return py_type; - } - - const lazy_import_info * info = &import_infos[index]; - PyObject * module = PyImport_ImportModule(info->module_name); - if (!module) { - return NULL; - } - py_type = PyObject_GetAttrString(module, info->object_name); - Py_DECREF(module); - if (!py_type) { - return NULL; - } - if (info->ensure_is_type && !PyType_Check(py_type)) { - PyErr_SetString(PyExc_RuntimeError, "Imported object is not a python type"); - return NULL; - } - - state->cached_imports[index] = py_type; - return py_type; -} - -static void clear_storage(PyObject * capsule) -{ - (void)capsule; - state_storage = NULL; -} - -int example_msgs__lazy_import_acquire() -{ - if (state_storage == NULL) { - lazy_import_state * state = PyMem_Malloc(sizeof(lazy_import_state)); - if (example_msgs__lazy_import_initialize(state) != 0) { - return 1; - } - state_storage = PyCapsule_New(state, NULL, clear_storage); - } else { - Py_INCREF(state_storage); - } - return 0; -} - -int example_msgs__lazy_import_release() -{ - Py_DECREF(state_storage); - return 0; -} diff --git a/rosidl_generator_py/example/_example_msgs_s.ep.rosidl_typesupport_c.c b/rosidl_generator_py/example/_example_msgs_s.ep.rosidl_typesupport_c.c deleted file mode 100644 index 910ce57a..00000000 --- a/rosidl_generator_py/example/_example_msgs_s.ep.rosidl_typesupport_c.c +++ /dev/null @@ -1,666 +0,0 @@ -// generated from rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em -// generated code does not contain a copyright notice -#include - -#include -#include -#include "rosidl_runtime_c/visibility_control.h" -#include "rosidl_runtime_c/message_type_support_struct.h" -#include "rosidl_runtime_c/service_type_support_struct.h" -#include "rosidl_runtime_c/action_type_support_struct.h" -#include "example_msgs/msg/detail/custom_message__type_support.h" -#include "example_msgs/msg/detail/custom_message__struct.h" -#include "example_msgs/msg/detail/custom_message__functions.h" - -static void * example_msgs__msg__custom_message__create_ros_message(void) -{ - return example_msgs__msg__CustomMessage__create(); -} - -static void example_msgs__msg__custom_message__destroy_ros_message(void * raw_ros_message) -{ - example_msgs__msg__CustomMessage * ros_message = (example_msgs__msg__CustomMessage *)raw_ros_message; - example_msgs__msg__CustomMessage__destroy(ros_message); -} - -ROSIDL_GENERATOR_C_IMPORT -bool example_msgs__msg__custom_message__convert_from_py(PyObject * _pymsg, void * ros_message); -ROSIDL_GENERATOR_C_IMPORT -PyObject * example_msgs__msg__custom_message__convert_to_py(void * raw_ros_message); - - -ROSIDL_GENERATOR_C_IMPORT -const rosidl_message_type_support_t * -ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, msg, CustomMessage); - -int8_t -_register_msg_type__msg__custom_message(PyObject * pymodule) -{ - int8_t err; - - PyObject * pyobject_create_ros_message = NULL; - pyobject_create_ros_message = PyCapsule_New( - (void *)&example_msgs__msg__custom_message__create_ros_message, - NULL, NULL); - if (!pyobject_create_ros_message) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "create_ros_message_msg__msg__custom_message", - pyobject_create_ros_message); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_create_ros_message); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_destroy_ros_message = NULL; - pyobject_destroy_ros_message = PyCapsule_New( - (void *)&example_msgs__msg__custom_message__destroy_ros_message, - NULL, NULL); - if (!pyobject_destroy_ros_message) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "destroy_ros_message_msg__msg__custom_message", - pyobject_destroy_ros_message); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_destroy_ros_message); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_convert_from_py = NULL; - pyobject_convert_from_py = PyCapsule_New( - (void *)&example_msgs__msg__custom_message__convert_from_py, - NULL, NULL); - if (!pyobject_convert_from_py) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "convert_from_py_msg__msg__custom_message", - pyobject_convert_from_py); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_convert_from_py); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_convert_to_py = NULL; - pyobject_convert_to_py = PyCapsule_New( - (void *)&example_msgs__msg__custom_message__convert_to_py, - NULL, NULL); - if (!pyobject_convert_to_py) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "convert_to_py_msg__msg__custom_message", - pyobject_convert_to_py); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_convert_to_py); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_type_support = NULL; - pyobject_type_support = PyCapsule_New( - (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, msg, CustomMessage), - NULL, NULL); - if (!pyobject_type_support) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "type_support_msg__msg__custom_message", - pyobject_type_support); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_type_support); - // previously added objects will be removed when the module is destroyed - return err; - } - return 0; -} - -// already included above -// #include -// already included above -// #include -// already included above -// #include "rosidl_runtime_c/visibility_control.h" -// already included above -// #include "rosidl_runtime_c/message_type_support_struct.h" -// already included above -// #include "rosidl_runtime_c/service_type_support_struct.h" -// already included above -// #include "rosidl_runtime_c/action_type_support_struct.h" -#include "example_msgs/srv/detail/custom_call__type_support.h" -#include "example_msgs/srv/detail/custom_call__struct.h" -#include "example_msgs/srv/detail/custom_call__functions.h" - -static void * example_msgs__srv__custom_call__request__create_ros_message(void) -{ - return example_msgs__srv__CustomCall_Request__create(); -} - -static void example_msgs__srv__custom_call__request__destroy_ros_message(void * raw_ros_message) -{ - example_msgs__srv__CustomCall_Request * ros_message = (example_msgs__srv__CustomCall_Request *)raw_ros_message; - example_msgs__srv__CustomCall_Request__destroy(ros_message); -} - -ROSIDL_GENERATOR_C_IMPORT -bool example_msgs__srv__custom_call__request__convert_from_py(PyObject * _pymsg, void * ros_message); -ROSIDL_GENERATOR_C_IMPORT -PyObject * example_msgs__srv__custom_call__request__convert_to_py(void * raw_ros_message); - - -ROSIDL_GENERATOR_C_IMPORT -const rosidl_message_type_support_t * -ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Request); - -int8_t -_register_msg_type__srv__custom_call__request(PyObject * pymodule) -{ - int8_t err; - - PyObject * pyobject_create_ros_message = NULL; - pyobject_create_ros_message = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__request__create_ros_message, - NULL, NULL); - if (!pyobject_create_ros_message) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "create_ros_message_msg__srv__custom_call__request", - pyobject_create_ros_message); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_create_ros_message); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_destroy_ros_message = NULL; - pyobject_destroy_ros_message = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__request__destroy_ros_message, - NULL, NULL); - if (!pyobject_destroy_ros_message) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "destroy_ros_message_msg__srv__custom_call__request", - pyobject_destroy_ros_message); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_destroy_ros_message); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_convert_from_py = NULL; - pyobject_convert_from_py = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__request__convert_from_py, - NULL, NULL); - if (!pyobject_convert_from_py) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "convert_from_py_msg__srv__custom_call__request", - pyobject_convert_from_py); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_convert_from_py); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_convert_to_py = NULL; - pyobject_convert_to_py = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__request__convert_to_py, - NULL, NULL); - if (!pyobject_convert_to_py) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "convert_to_py_msg__srv__custom_call__request", - pyobject_convert_to_py); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_convert_to_py); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_type_support = NULL; - pyobject_type_support = PyCapsule_New( - (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Request), - NULL, NULL); - if (!pyobject_type_support) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "type_support_msg__srv__custom_call__request", - pyobject_type_support); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_type_support); - // previously added objects will be removed when the module is destroyed - return err; - } - return 0; -} - -// already included above -// #include -// already included above -// #include -// already included above -// #include "rosidl_runtime_c/visibility_control.h" -// already included above -// #include "rosidl_runtime_c/message_type_support_struct.h" -// already included above -// #include "rosidl_runtime_c/service_type_support_struct.h" -// already included above -// #include "rosidl_runtime_c/action_type_support_struct.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__type_support.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__struct.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__functions.h" - -static void * example_msgs__srv__custom_call__response__create_ros_message(void) -{ - return example_msgs__srv__CustomCall_Response__create(); -} - -static void example_msgs__srv__custom_call__response__destroy_ros_message(void * raw_ros_message) -{ - example_msgs__srv__CustomCall_Response * ros_message = (example_msgs__srv__CustomCall_Response *)raw_ros_message; - example_msgs__srv__CustomCall_Response__destroy(ros_message); -} - -ROSIDL_GENERATOR_C_IMPORT -bool example_msgs__srv__custom_call__response__convert_from_py(PyObject * _pymsg, void * ros_message); -ROSIDL_GENERATOR_C_IMPORT -PyObject * example_msgs__srv__custom_call__response__convert_to_py(void * raw_ros_message); - - -ROSIDL_GENERATOR_C_IMPORT -const rosidl_message_type_support_t * -ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Response); - -int8_t -_register_msg_type__srv__custom_call__response(PyObject * pymodule) -{ - int8_t err; - - PyObject * pyobject_create_ros_message = NULL; - pyobject_create_ros_message = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__response__create_ros_message, - NULL, NULL); - if (!pyobject_create_ros_message) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "create_ros_message_msg__srv__custom_call__response", - pyobject_create_ros_message); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_create_ros_message); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_destroy_ros_message = NULL; - pyobject_destroy_ros_message = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__response__destroy_ros_message, - NULL, NULL); - if (!pyobject_destroy_ros_message) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "destroy_ros_message_msg__srv__custom_call__response", - pyobject_destroy_ros_message); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_destroy_ros_message); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_convert_from_py = NULL; - pyobject_convert_from_py = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__response__convert_from_py, - NULL, NULL); - if (!pyobject_convert_from_py) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "convert_from_py_msg__srv__custom_call__response", - pyobject_convert_from_py); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_convert_from_py); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_convert_to_py = NULL; - pyobject_convert_to_py = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__response__convert_to_py, - NULL, NULL); - if (!pyobject_convert_to_py) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "convert_to_py_msg__srv__custom_call__response", - pyobject_convert_to_py); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_convert_to_py); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_type_support = NULL; - pyobject_type_support = PyCapsule_New( - (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Response), - NULL, NULL); - if (!pyobject_type_support) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "type_support_msg__srv__custom_call__response", - pyobject_type_support); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_type_support); - // previously added objects will be removed when the module is destroyed - return err; - } - return 0; -} - -// already included above -// #include -// already included above -// #include -// already included above -// #include "rosidl_runtime_c/visibility_control.h" -// already included above -// #include "rosidl_runtime_c/message_type_support_struct.h" -// already included above -// #include "rosidl_runtime_c/service_type_support_struct.h" -// already included above -// #include "rosidl_runtime_c/action_type_support_struct.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__type_support.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__struct.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__functions.h" - -static void * example_msgs__srv__custom_call__event__create_ros_message(void) -{ - return example_msgs__srv__CustomCall_Event__create(); -} - -static void example_msgs__srv__custom_call__event__destroy_ros_message(void * raw_ros_message) -{ - example_msgs__srv__CustomCall_Event * ros_message = (example_msgs__srv__CustomCall_Event *)raw_ros_message; - example_msgs__srv__CustomCall_Event__destroy(ros_message); -} - -ROSIDL_GENERATOR_C_IMPORT -bool example_msgs__srv__custom_call__event__convert_from_py(PyObject * _pymsg, void * ros_message); -ROSIDL_GENERATOR_C_IMPORT -PyObject * example_msgs__srv__custom_call__event__convert_to_py(void * raw_ros_message); - - -ROSIDL_GENERATOR_C_IMPORT -const rosidl_message_type_support_t * -ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Event); - -int8_t -_register_msg_type__srv__custom_call__event(PyObject * pymodule) -{ - int8_t err; - - PyObject * pyobject_create_ros_message = NULL; - pyobject_create_ros_message = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__event__create_ros_message, - NULL, NULL); - if (!pyobject_create_ros_message) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "create_ros_message_msg__srv__custom_call__event", - pyobject_create_ros_message); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_create_ros_message); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_destroy_ros_message = NULL; - pyobject_destroy_ros_message = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__event__destroy_ros_message, - NULL, NULL); - if (!pyobject_destroy_ros_message) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "destroy_ros_message_msg__srv__custom_call__event", - pyobject_destroy_ros_message); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_destroy_ros_message); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_convert_from_py = NULL; - pyobject_convert_from_py = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__event__convert_from_py, - NULL, NULL); - if (!pyobject_convert_from_py) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "convert_from_py_msg__srv__custom_call__event", - pyobject_convert_from_py); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_convert_from_py); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_convert_to_py = NULL; - pyobject_convert_to_py = PyCapsule_New( - (void *)&example_msgs__srv__custom_call__event__convert_to_py, - NULL, NULL); - if (!pyobject_convert_to_py) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "convert_to_py_msg__srv__custom_call__event", - pyobject_convert_to_py); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_convert_to_py); - // previously added objects will be removed when the module is destroyed - return err; - } - - PyObject * pyobject_type_support = NULL; - pyobject_type_support = PyCapsule_New( - (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(example_msgs, srv, CustomCall_Event), - NULL, NULL); - if (!pyobject_type_support) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "type_support_msg__srv__custom_call__event", - pyobject_type_support); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_type_support); - // previously added objects will be removed when the module is destroyed - return err; - } - return 0; -} - -ROSIDL_GENERATOR_C_IMPORT -const rosidl_service_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, example_msgs, srv, CustomCall)(); - -int8_t -_register_srv_type__srv__custom_call(PyObject * pymodule) -{ - int8_t err; - PyObject * pyobject_type_support = NULL; - pyobject_type_support = PyCapsule_New( - (void *)ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, example_msgs, srv, CustomCall)(), - NULL, NULL); - if (!pyobject_type_support) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "type_support_srv__srv__custom_call", - pyobject_type_support); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_type_support); - // previously added objects will be removed when the module is destroyed - return err; - } - return 0; -} - -#include "./_example_msgs_decl.h" - -static PyMethodDef example_msgs__methods[] = { - {NULL, NULL, 0, NULL} /* sentinel */ -}; - -static int -_example_msgs_clear(PyObject * module) -{ - (void)module; - example_msgs__lazy_import_release(); - return 0; -} - -static void -_example_msgs_free(void * module) -{ - _example_msgs_clear((PyObject *)module); -} - - -static struct PyModuleDef example_msgs__module = { - PyModuleDef_HEAD_INIT, - "_example_msgs_support", - "_example_msgs_doc", - -1, /* -1 means that the module keeps state in global variables */ - example_msgs__methods, - NULL, - NULL, - _example_msgs_clear, - _example_msgs_free, -}; - - -PyMODINIT_FUNC -PyInit_example_msgs_s__rosidl_typesupport_c(void) -{ - PyObject * pymodule = NULL; - pymodule = PyModule_Create(&example_msgs__module); - if (!pymodule) { - return NULL; - } - int8_t err; - - err = _register_msg_type__msg__custom_message(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_msg_type__srv__custom_call__request(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_msg_type__srv__custom_call__response(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_msg_type__srv__custom_call__event(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_srv_type__srv__custom_call(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - example_msgs__lazy_import_acquire(); - return pymodule; -} diff --git a/rosidl_generator_py/example/msg/CustomMessage.msg b/rosidl_generator_py/example/msg/CustomMessage.msg deleted file mode 100644 index d54d663b..00000000 --- a/rosidl_generator_py/example/msg/CustomMessage.msg +++ /dev/null @@ -1,5 +0,0 @@ -uint16 x -builtin_interfaces/Time ts -int16[3] fixed_seq -int16[<=3] limited_seq -int16[] unlimited_seq diff --git a/rosidl_generator_py/example/msg/__init__.py b/rosidl_generator_py/example/msg/__init__.py deleted file mode 100644 index a2b9271b..00000000 --- a/rosidl_generator_py/example/msg/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from example_msgs.msg._custom_message import CustomMessage # noqa: F401 diff --git a/rosidl_generator_py/example/msg/_custom_message.py b/rosidl_generator_py/example/msg/_custom_message.py deleted file mode 100644 index 703e4123..00000000 --- a/rosidl_generator_py/example/msg/_custom_message.py +++ /dev/null @@ -1,291 +0,0 @@ -# generated from rosidl_generator_py/resource/_idl.py.em -# with input from example_msgs:msg/CustomMessage.idl -# generated code does not contain a copyright notice - - -# Import statements for member types - -# Member 'limited_seq' -# Member 'unlimited_seq' -import array # noqa: E402, I100 - -import builtins # noqa: E402, I100 - -import example_msgs._example_msgs_bases as _bases # noqa: E402, I100 - -# Member 'fixed_seq' -import numpy # noqa: E402, I100 - -import rosidl_parser.definition # noqa: E402, I100 - - -class Metaclass_CustomMessage(type): - """Metaclass of message 'CustomMessage'.""" - - _CREATE_ROS_MESSAGE = None - _CONVERT_FROM_PY = None - _CONVERT_TO_PY = None - _DESTROY_ROS_MESSAGE = None - _TYPE_SUPPORT = None - - __constants = { - } - - def __new__(cls, *args): - new_type = super().__new__(cls, *args) - - # Ugly hack here. - # There are two purposes for __slots__ field of message class: - # 1) __slots__ field is used in ROS as a list of message members. - # Number of ROS packages rely on its value. - # 2) defining __slots__ in Python class prevents adding __dict__ - # to class instances. This behvior is desirable. - # If #1 defined in message class body, then base class member descriptors are - # overriden and no longer can be used. On the other side, any __slots__ value - # should be defined to guaratee #2. - # So we define empty list in message class body and modify it after type object - # constructed. This is neither prohibited, nor encouraged by CPython documentation. - new_type.__slots__ += [ - '_x', - '_ts', - '_fixed_seq', - '_limited_seq', - '_unlimited_seq', - ] - return new_type - - @classmethod - def __import_type_support__(cls): - try: - from rosidl_generator_py import import_type_support - module = import_type_support('example_msgs') - except ImportError: - import logging - import traceback - logger = logging.getLogger( - 'example_msgs.msg.CustomMessage') - logger.debug( - 'Failed to import needed modules for type support:\n' + - traceback.format_exc()) - else: - cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__msg__custom_message - cls._CONVERT_FROM_PY = module.convert_from_py_msg__msg__custom_message - cls._CONVERT_TO_PY = module.convert_to_py_msg__msg__custom_message - cls._TYPE_SUPPORT = module.type_support_msg__msg__custom_message - cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__msg__custom_message - - from builtin_interfaces.msg import Time - if Time.__class__._TYPE_SUPPORT is None: - Time.__class__.__import_type_support__() - - @classmethod - def __prepare__(cls, name, bases, **kwargs): - # list constant names here so that they appear in the help text of - # the message class under "Data and other attributes defined here:" - # as well as populate each message instance - return { - } - - -class CustomMessage(_bases.CustomMessageBase, metaclass=Metaclass_CustomMessage): - """Message class 'CustomMessage'.""" - - # This field is modified after class creation. - # See the comment to Metaclass_CustomMessage.__new__ - __slots__ = [] - - _fields_and_field_types = { - 'x': 'uint16', - 'ts': 'builtin_interfaces/Time', - 'fixed_seq': 'int16[3]', - 'limited_seq': 'sequence', - 'unlimited_seq': 'sequence', - } - - SLOT_TYPES = ( - rosidl_parser.definition.BasicType('uint16'), # noqa: E501 - rosidl_parser.definition.NamespacedType(['builtin_interfaces', 'msg'], 'Time'), # noqa: E501 - rosidl_parser.definition.Array(rosidl_parser.definition.BasicType('int16'), 3), # noqa: E501 - rosidl_parser.definition.BoundedSequence(rosidl_parser.definition.BasicType('int16'), 3), # noqa: E501 - rosidl_parser.definition.UnboundedSequence(rosidl_parser.definition.BasicType('int16')), # noqa: E501 - ) - - 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__)) - self.x = kwargs.get('x', int()) - from builtin_interfaces.msg import Time - self.ts = kwargs.get('ts', Time()) - if 'fixed_seq' not in kwargs: - self.fixed_seq = numpy.zeros(3, dtype=numpy.int16) - else: - self.fixed_seq = numpy.array(kwargs.get('fixed_seq'), dtype=numpy.int16) - assert self.fixed_seq.shape == (3, ) - self.limited_seq = array.array('h', kwargs.get('limited_seq', [])) - self.unlimited_seq = array.array('h', kwargs.get('unlimited_seq', [])) - - def __repr__(self): - typename = self.__class__.__module__.split('.') - typename.pop() - typename.append(self.__class__.__name__) - args = [] - for s, t in zip(self.__slots__, self.SLOT_TYPES): - field = getattr(self, s) - fieldstr = repr(field) - # We use Python array type for fields that can be directly stored - # in them, and "normal" sequences for everything else. If it is - # a type that we store in an array, strip off the 'array' portion. - if ( - isinstance(t, rosidl_parser.definition.AbstractSequence) and - isinstance(t.value_type, rosidl_parser.definition.BasicType) and - t.value_type.typename in ['float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] - ): - if len(field) == 0: - fieldstr = '[]' - else: - assert fieldstr.startswith('array(') - prefix = "array('X', " - suffix = ')' - fieldstr = fieldstr[len(prefix):-len(suffix)] - args.append(s[1:] + '=' + fieldstr) - return '%s(%s)' % ('.'.join(typename), ', '.join(args)) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - if self.x != other.x: - return False - if self.ts != other.ts: - return False - if all(self.fixed_seq != other.fixed_seq): - return False - if self.limited_seq != other.limited_seq: - return False - if self.unlimited_seq != other.unlimited_seq: - return False - return True - - @classmethod - def get_fields_and_field_types(cls): - from copy import copy - return copy(cls._fields_and_field_types) - - @builtins.property - def x(self): - """Message field 'x'.""" - return self._x - - @x.setter - def x(self, value): - if __debug__: - assert \ - isinstance(value, int), \ - "The 'x' field must be of type 'int'" - assert value >= 0 and value < 65536, \ - "The 'x' field must be an unsigned integer in [0, 65535]" - self._x = value - - @builtins.property - def ts(self): - """Message field 'ts'.""" - return self._ts - - @ts.setter - def ts(self, value): - if __debug__: - from builtin_interfaces.msg import Time - assert \ - isinstance(value, Time), \ - "The 'ts' field must be a sub message of type 'Time'" - self._ts = value - - @builtins.property - def fixed_seq(self): - """Message field 'fixed_seq'.""" - return self._fixed_seq - - @fixed_seq.setter - def fixed_seq(self, value): - if isinstance(value, numpy.ndarray): - assert value.dtype == numpy.int16, \ - "The 'fixed_seq' numpy.ndarray() must have the dtype of 'numpy.int16'" - assert value.size == 3, \ - "The 'fixed_seq' numpy.ndarray() must have a size of 3" - self._fixed_seq = value - return - if __debug__: - from collections.abc import Sequence - from collections.abc import Set - from collections import UserList - from collections import UserString - assert \ - ((isinstance(value, Sequence) or - isinstance(value, Set) or - isinstance(value, UserList)) and - not isinstance(value, str) and - not isinstance(value, UserString) and - len(value) == 3 and - all(isinstance(v, int) for v in value) and - all(val >= -32768 and val < 32768 for val in value)), \ - "The 'fixed_seq' field must be a set or sequence with length 3 and each value of type 'int' and each integer in [-32768, 32767]" - self._fixed_seq = numpy.array(value, dtype=numpy.int16) - - @builtins.property - def limited_seq(self): - """Message field 'limited_seq'.""" - return self._limited_seq - - @limited_seq.setter - def limited_seq(self, value): - if isinstance(value, array.array): - assert value.typecode == 'h', \ - "The 'limited_seq' array.array() must have the type code of 'h'" - assert len(value) <= 3, \ - "The 'limited_seq' array.array() must have a size <= 3" - self._limited_seq = value - return - if __debug__: - from collections.abc import Sequence - from collections.abc import Set - from collections import UserList - from collections import UserString - assert \ - ((isinstance(value, Sequence) or - isinstance(value, Set) or - isinstance(value, UserList)) and - not isinstance(value, str) and - not isinstance(value, UserString) and - len(value) <= 3 and - all(isinstance(v, int) for v in value) and - all(val >= -32768 and val < 32768 for val in value)), \ - "The 'limited_seq' field must be a set or sequence with length <= 3 and each value of type 'int' and each integer in [-32768, 32767]" - self._limited_seq = array.array('h', value) - - @builtins.property - def unlimited_seq(self): - """Message field 'unlimited_seq'.""" - return self._unlimited_seq - - @unlimited_seq.setter - def unlimited_seq(self, value): - if isinstance(value, array.array): - assert value.typecode == 'h', \ - "The 'unlimited_seq' array.array() must have the type code of 'h'" - self._unlimited_seq = value - return - if __debug__: - from collections.abc import Sequence - from collections.abc import Set - from collections import UserList - from collections import UserString - assert \ - ((isinstance(value, Sequence) or - isinstance(value, Set) or - isinstance(value, UserList)) and - not isinstance(value, str) and - not isinstance(value, UserString) and - all(isinstance(v, int) for v in value) and - all(val >= -32768 and val < 32768 for val in value)), \ - "The 'unlimited_seq' field must be a set or sequence and each value of type 'int' and each integer in [-32768, 32767]" - self._unlimited_seq = array.array('h', value) diff --git a/rosidl_generator_py/example/msg/_custom_message_s.c b/rosidl_generator_py/example/msg/_custom_message_s.c deleted file mode 100644 index 97e84d93..00000000 --- a/rosidl_generator_py/example/msg/_custom_message_s.c +++ /dev/null @@ -1,386 +0,0 @@ -// generated from rosidl_generator_py/resource/_idl_support.c.em -// with input from example_msgs:msg/CustomMessage.idl -// generated code does not contain a copyright notice -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#include -#include -#ifndef _WIN32 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-function" -#endif -#include "numpy/ndarrayobject.h" -#ifndef _WIN32 -# pragma GCC diagnostic pop -#endif -#include "rosidl_runtime_c/visibility_control.h" -#include "example_msgs/msg/detail/custom_message__struct.h" -#include "example_msgs/msg/detail/custom_message__functions.h" -#include "../_example_msgs_decl.h" - -#include "rosidl_runtime_c/primitives_sequence.h" -#include "rosidl_runtime_c/primitives_sequence_functions.h" - -ROSIDL_GENERATOR_C_IMPORT -bool builtin_interfaces__msg__time__convert_from_py(PyObject * _pymsg, void * _ros_message); -ROSIDL_GENERATOR_C_IMPORT -PyObject * builtin_interfaces__msg__time__convert_to_py(void * raw_ros_message); - -ROSIDL_GENERATOR_C_EXPORT -bool example_msgs__msg__custom_message__convert_from_py(PyObject * _pymsg, void * _ros_message) -{ - // check that the passed message is of the expected Python class - { - PyTypeObject * py_type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__MSG__CUSTOM_MESSAGE__IMPORT_INDEX); - assert(Py_TYPE(_pymsg) == py_type); - } - example_msgs__msg__CustomMessage * ros_message = _ros_message; - - CustomMessageBase * base_msg = (CustomMessageBase *)_pymsg; - { // x - ros_message->x = base_msg->_x; - } - { // ts - PyObject * field = base_msg->_ts; - if (!field) { - return false; - } - if (!builtin_interfaces__msg__time__convert_from_py(field, &ros_message->ts)) { - return false; - } - } - { // fixed_seq - PyObject * field = base_msg->_fixed_seq; - if (!field) { - return false; - } - { - // TODO(dirk-thomas) use a better way to check the type before casting - assert(field->ob_type != NULL); - assert(field->ob_type->tp_name != NULL); - assert(strcmp(field->ob_type->tp_name, "numpy.ndarray") == 0); - PyArrayObject * seq_field = (PyArrayObject *)field; - Py_INCREF(seq_field); - assert(PyArray_NDIM(seq_field) == 1); - assert(PyArray_TYPE(seq_field) == NPY_INT16); - Py_ssize_t size = 3; - int16_t * dest = ros_message->fixed_seq; - for (Py_ssize_t i = 0; i < size; ++i) { - int16_t tmp = *(npy_int16 *)PyArray_GETPTR1(seq_field, i); - memcpy(&dest[i], &tmp, sizeof(int16_t)); - } - Py_DECREF(seq_field); - } - } - { // limited_seq - PyObject * field = base_msg->_limited_seq; - if (!field) { - return false; - } - if (PyObject_CheckBuffer(field)) { - // Optimization for converting arrays of primitives - Py_buffer view; - int rc = PyObject_GetBuffer(field, &view, PyBUF_SIMPLE); - if (rc < 0) { - return false; - } - Py_ssize_t size = view.len / sizeof(int16_t); - if (!rosidl_runtime_c__int16__Sequence__init(&(ros_message->limited_seq), size)) { - PyErr_SetString(PyExc_RuntimeError, "unable to create int16__Sequence ros_message"); - PyBuffer_Release(&view); - return false; - } - int16_t * dest = ros_message->limited_seq.data; - rc = PyBuffer_ToContiguous(dest, &view, view.len, 'C'); - if (rc < 0) { - PyBuffer_Release(&view); - return false; - } - PyBuffer_Release(&view); - } else { - PyObject * seq_field = PySequence_Fast(field, "expected a sequence in 'limited_seq'"); - if (!seq_field) { - return false; - } - Py_ssize_t size = PySequence_Size(field); - if (-1 == size) { - Py_DECREF(seq_field); - return false; - } - if (!rosidl_runtime_c__int16__Sequence__init(&(ros_message->limited_seq), size)) { - PyErr_SetString(PyExc_RuntimeError, "unable to create int16__Sequence ros_message"); - Py_DECREF(seq_field); - return false; - } - int16_t * dest = ros_message->limited_seq.data; - for (Py_ssize_t i = 0; i < size; ++i) { - PyObject * item = PySequence_Fast_GET_ITEM(seq_field, i); - if (!item) { - Py_DECREF(seq_field); - return false; - } - assert(PyLong_Check(item)); - int16_t tmp = (int16_t)PyLong_AsLong(item); - memcpy(&dest[i], &tmp, sizeof(int16_t)); - } - Py_DECREF(seq_field); - } - } - { // unlimited_seq - PyObject * field = base_msg->_unlimited_seq; - if (!field) { - return false; - } - if (PyObject_CheckBuffer(field)) { - // Optimization for converting arrays of primitives - Py_buffer view; - int rc = PyObject_GetBuffer(field, &view, PyBUF_SIMPLE); - if (rc < 0) { - return false; - } - Py_ssize_t size = view.len / sizeof(int16_t); - if (!rosidl_runtime_c__int16__Sequence__init(&(ros_message->unlimited_seq), size)) { - PyErr_SetString(PyExc_RuntimeError, "unable to create int16__Sequence ros_message"); - PyBuffer_Release(&view); - return false; - } - int16_t * dest = ros_message->unlimited_seq.data; - rc = PyBuffer_ToContiguous(dest, &view, view.len, 'C'); - if (rc < 0) { - PyBuffer_Release(&view); - return false; - } - PyBuffer_Release(&view); - } else { - PyObject * seq_field = PySequence_Fast(field, "expected a sequence in 'unlimited_seq'"); - if (!seq_field) { - return false; - } - Py_ssize_t size = PySequence_Size(field); - if (-1 == size) { - Py_DECREF(seq_field); - return false; - } - if (!rosidl_runtime_c__int16__Sequence__init(&(ros_message->unlimited_seq), size)) { - PyErr_SetString(PyExc_RuntimeError, "unable to create int16__Sequence ros_message"); - Py_DECREF(seq_field); - return false; - } - int16_t * dest = ros_message->unlimited_seq.data; - for (Py_ssize_t i = 0; i < size; ++i) { - PyObject * item = PySequence_Fast_GET_ITEM(seq_field, i); - if (!item) { - Py_DECREF(seq_field); - return false; - } - assert(PyLong_Check(item)); - int16_t tmp = (int16_t)PyLong_AsLong(item); - memcpy(&dest[i], &tmp, sizeof(int16_t)); - } - Py_DECREF(seq_field); - } - } - - return true; -} - -ROSIDL_GENERATOR_C_EXPORT -PyObject * example_msgs__msg__custom_message__convert_to_py(void * raw_ros_message) -{ - /* NOTE(esteve): Call constructor of CustomMessage */ - CustomMessageBase * _pymessage = NULL; - { - PyTypeObject * type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__MSG__CUSTOM_MESSAGE__IMPORT_INDEX); - if (!type) { - return NULL; - } - assert(type->tp_new); - - PyObject * empty_tuple = PyTuple_New(0); - if (!empty_tuple) { - return NULL; - } - - _pymessage = (CustomMessageBase *)type->tp_new(type, empty_tuple, NULL); - Py_DECREF(empty_tuple); - if (!_pymessage) { - return NULL; - } - } - example_msgs__msg__CustomMessage * ros_message = (example_msgs__msg__CustomMessage *)raw_ros_message; - { // x - _pymessage->_x = ros_message->x; - } - { // ts - PyObject * field = NULL; - field = builtin_interfaces__msg__time__convert_to_py(&ros_message->ts); - if (!field) { - return NULL; - } - // reference is transfered to object - _pymessage->_ts = field; - } - { // fixed_seq - PyObject * field = NULL; - - PyObject * array_type = example_msgs__lazy_import(NULL, NUMPY__NDARRAY__IMPORT_INDEX); - if (!array_type) { - return NULL; - } - PyObject * element_type = example_msgs__lazy_import(NULL, NUMPY__INT16__IMPORT_INDEX); - if (!element_type) { - return NULL; - } - PyObject * dims = Py_BuildValue("(i)", 3); - field = PyObject_CallFunctionObjArgs(array_type, dims, element_type, NULL); - Py_DECREF(dims); - assert(strcmp(field->ob_type->tp_name, "numpy.ndarray") == 0); - PyArrayObject * seq_field = (PyArrayObject *)field; - assert(PyArray_NDIM(seq_field) == 1); - assert(PyArray_TYPE(seq_field) == NPY_INT16); - assert(sizeof(npy_int16) == sizeof(int16_t)); - npy_int16 * dst = (npy_int16 *)PyArray_GETPTR1(seq_field, 0); - int16_t * src = &(ros_message->fixed_seq[0]); - memcpy(dst, src, 3 * sizeof(int16_t)); - // reference is transfered to object - _pymessage->_fixed_seq = field; - } - { // limited_seq - PyObject * field = NULL; - { - PyObject * array_type = example_msgs__lazy_import(NULL, ARRAY__ARRAY__IMPORT_INDEX); - if (!array_type) { - return NULL; - } - PyObject * type_code = PyUnicode_FromOrdinal('h'); - assert(type_code); - - field = PyObject_CallFunctionObjArgs(array_type, type_code, NULL); - Py_DECREF(type_code); - if (!field) { - return NULL; - } - } - assert(field->ob_type != NULL); - assert(field->ob_type->tp_name != NULL); - assert(strcmp(field->ob_type->tp_name, "array.array") == 0); - // ensure that itemsize matches the sizeof of the ROS message field - PyObject * itemsize_attr = PyObject_GetAttrString(field, "itemsize"); - assert(itemsize_attr != NULL); - size_t itemsize = PyLong_AsSize_t(itemsize_attr); - Py_DECREF(itemsize_attr); - if (itemsize != sizeof(int16_t)) { - PyErr_SetString(PyExc_RuntimeError, "itemsize doesn't match expectation"); - Py_DECREF(field); - return NULL; - } - // clear the array, poor approach to remove potential default values - Py_ssize_t length = PyObject_Length(field); - if (-1 == length) { - Py_DECREF(field); - return NULL; - } - if (length > 0) { - PyObject * pop = PyObject_GetAttrString(field, "pop"); - assert(pop != NULL); - for (Py_ssize_t i = 0; i < length; ++i) { - PyObject * ret = PyObject_CallFunctionObjArgs(pop, NULL); - if (!ret) { - Py_DECREF(pop); - Py_DECREF(field); - return NULL; - } - Py_DECREF(ret); - } - Py_DECREF(pop); - } - if (ros_message->limited_seq.size > 0) { - // populating the array.array using the frombytes method - PyObject * frombytes = PyObject_GetAttrString(field, "frombytes"); - assert(frombytes != NULL); - int16_t * src = &(ros_message->limited_seq.data[0]); - PyObject * data = PyBytes_FromStringAndSize((const char *)src, ros_message->limited_seq.size * sizeof(int16_t)); - assert(data != NULL); - PyObject * ret = PyObject_CallFunctionObjArgs(frombytes, data, NULL); - Py_DECREF(data); - Py_DECREF(frombytes); - if (!ret) { - Py_DECREF(field); - return NULL; - } - Py_DECREF(ret); - } - // reference is transfered to object - _pymessage->_limited_seq = field; - } - { // unlimited_seq - PyObject * field = NULL; - { - PyObject * array_type = example_msgs__lazy_import(NULL, ARRAY__ARRAY__IMPORT_INDEX); - if (!array_type) { - return NULL; - } - PyObject * type_code = PyUnicode_FromOrdinal('h'); - assert(type_code); - - field = PyObject_CallFunctionObjArgs(array_type, type_code, NULL); - Py_DECREF(type_code); - if (!field) { - return NULL; - } - } - assert(field->ob_type != NULL); - assert(field->ob_type->tp_name != NULL); - assert(strcmp(field->ob_type->tp_name, "array.array") == 0); - // ensure that itemsize matches the sizeof of the ROS message field - PyObject * itemsize_attr = PyObject_GetAttrString(field, "itemsize"); - assert(itemsize_attr != NULL); - size_t itemsize = PyLong_AsSize_t(itemsize_attr); - Py_DECREF(itemsize_attr); - if (itemsize != sizeof(int16_t)) { - PyErr_SetString(PyExc_RuntimeError, "itemsize doesn't match expectation"); - Py_DECREF(field); - return NULL; - } - // clear the array, poor approach to remove potential default values - Py_ssize_t length = PyObject_Length(field); - if (-1 == length) { - Py_DECREF(field); - return NULL; - } - if (length > 0) { - PyObject * pop = PyObject_GetAttrString(field, "pop"); - assert(pop != NULL); - for (Py_ssize_t i = 0; i < length; ++i) { - PyObject * ret = PyObject_CallFunctionObjArgs(pop, NULL); - if (!ret) { - Py_DECREF(pop); - Py_DECREF(field); - return NULL; - } - Py_DECREF(ret); - } - Py_DECREF(pop); - } - if (ros_message->unlimited_seq.size > 0) { - // populating the array.array using the frombytes method - PyObject * frombytes = PyObject_GetAttrString(field, "frombytes"); - assert(frombytes != NULL); - int16_t * src = &(ros_message->unlimited_seq.data[0]); - PyObject * data = PyBytes_FromStringAndSize((const char *)src, ros_message->unlimited_seq.size * sizeof(int16_t)); - assert(data != NULL); - PyObject * ret = PyObject_CallFunctionObjArgs(frombytes, data, NULL); - Py_DECREF(data); - Py_DECREF(frombytes); - if (!ret) { - Py_DECREF(field); - return NULL; - } - Py_DECREF(ret); - } - // reference is transfered to object - _pymessage->_unlimited_seq = field; - } - - // ownership of _pymessage is transferred to the caller - return (PyObject *)_pymessage; -} diff --git a/rosidl_generator_py/example/srv/CustomCall.srv b/rosidl_generator_py/example/srv/CustomCall.srv deleted file mode 100644 index 1ab4c8a2..00000000 --- a/rosidl_generator_py/example/srv/CustomCall.srv +++ /dev/null @@ -1,3 +0,0 @@ -int32 my_param ---- -int32 my_result diff --git a/rosidl_generator_py/example/srv/__init__.py b/rosidl_generator_py/example/srv/__init__.py deleted file mode 100644 index 1340e40c..00000000 --- a/rosidl_generator_py/example/srv/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from example_msgs.srv._custom_call import CustomCall # noqa: F401 -from example_msgs.srv._custom_call import CustomCall_Event # noqa: F401 -from example_msgs.srv._custom_call import CustomCall_Request # noqa: F401 -from example_msgs.srv._custom_call import CustomCall_Response # noqa: F401 diff --git a/rosidl_generator_py/example/srv/_custom_call.py b/rosidl_generator_py/example/srv/_custom_call.py deleted file mode 100644 index 2d16faca..00000000 --- a/rosidl_generator_py/example/srv/_custom_call.py +++ /dev/null @@ -1,546 +0,0 @@ -# generated from rosidl_generator_py/resource/_idl.py.em -# with input from example_msgs:srv/CustomCall.idl -# generated code does not contain a copyright notice - - -# Import statements for member types - -import builtins # noqa: E402, I100 - -import example_msgs._example_msgs_bases as _bases # noqa: E402, I100 - -import rosidl_parser.definition # noqa: E402, I100 - - -class Metaclass_CustomCall_Request(type): - """Metaclass of message 'CustomCall_Request'.""" - - _CREATE_ROS_MESSAGE = None - _CONVERT_FROM_PY = None - _CONVERT_TO_PY = None - _DESTROY_ROS_MESSAGE = None - _TYPE_SUPPORT = None - - __constants = { - } - - def __new__(cls, *args): - new_type = super().__new__(cls, *args) - - # Ugly hack here. - # There are two purposes for __slots__ field of message class: - # 1) __slots__ field is used in ROS as a list of message members. - # Number of ROS packages rely on its value. - # 2) defining __slots__ in Python class prevents adding __dict__ - # to class instances. This behvior is desirable. - # If #1 defined in message class body, then base class member descriptors are - # overriden and no longer can be used. On the other side, any __slots__ value - # should be defined to guaratee #2. - # So we define empty list in message class body and modify it after type object - # constructed. This is neither prohibited, nor encouraged by CPython documentation. - new_type.__slots__ += [ - '_my_param', - ] - return new_type - - @classmethod - def __import_type_support__(cls): - try: - from rosidl_generator_py import import_type_support - module = import_type_support('example_msgs') - except ImportError: - import logging - import traceback - logger = logging.getLogger( - 'example_msgs.srv.CustomCall_Request') - logger.debug( - 'Failed to import needed modules for type support:\n' + - traceback.format_exc()) - else: - cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__srv__custom_call__request - cls._CONVERT_FROM_PY = module.convert_from_py_msg__srv__custom_call__request - cls._CONVERT_TO_PY = module.convert_to_py_msg__srv__custom_call__request - cls._TYPE_SUPPORT = module.type_support_msg__srv__custom_call__request - cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__srv__custom_call__request - - @classmethod - def __prepare__(cls, name, bases, **kwargs): - # list constant names here so that they appear in the help text of - # the message class under "Data and other attributes defined here:" - # as well as populate each message instance - return { - } - - -class CustomCall_Request(_bases.CustomCall_RequestBase, metaclass=Metaclass_CustomCall_Request): - """Message class 'CustomCall_Request'.""" - - # This field is modified after class creation. - # See the comment to Metaclass_CustomCall_Request.__new__ - __slots__ = [] - - _fields_and_field_types = { - 'my_param': 'int32', - } - - SLOT_TYPES = ( - rosidl_parser.definition.BasicType('int32'), # noqa: E501 - ) - - 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__)) - self.my_param = kwargs.get('my_param', int()) - - def __repr__(self): - typename = self.__class__.__module__.split('.') - typename.pop() - typename.append(self.__class__.__name__) - args = [] - for s, t in zip(self.__slots__, self.SLOT_TYPES): - field = getattr(self, s) - fieldstr = repr(field) - # We use Python array type for fields that can be directly stored - # in them, and "normal" sequences for everything else. If it is - # a type that we store in an array, strip off the 'array' portion. - if ( - isinstance(t, rosidl_parser.definition.AbstractSequence) and - isinstance(t.value_type, rosidl_parser.definition.BasicType) and - t.value_type.typename in ['float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] - ): - if len(field) == 0: - fieldstr = '[]' - else: - assert fieldstr.startswith('array(') - prefix = "array('X', " - suffix = ')' - fieldstr = fieldstr[len(prefix):-len(suffix)] - args.append(s[1:] + '=' + fieldstr) - return '%s(%s)' % ('.'.join(typename), ', '.join(args)) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - if self.my_param != other.my_param: - return False - return True - - @classmethod - def get_fields_and_field_types(cls): - from copy import copy - return copy(cls._fields_and_field_types) - - @builtins.property - def my_param(self): - """Message field 'my_param'.""" - return self._my_param - - @my_param.setter - def my_param(self, value): - if __debug__: - assert \ - isinstance(value, int), \ - "The 'my_param' field must be of type 'int'" - assert value >= -2147483648 and value < 2147483648, \ - "The 'my_param' field must be an integer in [-2147483648, 2147483647]" - self._my_param = value - - -# Import statements for member types - -# already imported above -# import builtins - -# already imported above -# import example_msgs._example_msgs_bases as _bases - -# already imported above -# import rosidl_parser.definition - - -class Metaclass_CustomCall_Response(type): - """Metaclass of message 'CustomCall_Response'.""" - - _CREATE_ROS_MESSAGE = None - _CONVERT_FROM_PY = None - _CONVERT_TO_PY = None - _DESTROY_ROS_MESSAGE = None - _TYPE_SUPPORT = None - - __constants = { - } - - def __new__(cls, *args): - new_type = super().__new__(cls, *args) - - # Ugly hack here. - # There are two purposes for __slots__ field of message class: - # 1) __slots__ field is used in ROS as a list of message members. - # Number of ROS packages rely on its value. - # 2) defining __slots__ in Python class prevents adding __dict__ - # to class instances. This behvior is desirable. - # If #1 defined in message class body, then base class member descriptors are - # overriden and no longer can be used. On the other side, any __slots__ value - # should be defined to guaratee #2. - # So we define empty list in message class body and modify it after type object - # constructed. This is neither prohibited, nor encouraged by CPython documentation. - new_type.__slots__ += [ - '_my_result', - ] - return new_type - - @classmethod - def __import_type_support__(cls): - try: - from rosidl_generator_py import import_type_support - module = import_type_support('example_msgs') - except ImportError: - import logging - import traceback - logger = logging.getLogger( - 'example_msgs.srv.CustomCall_Response') - logger.debug( - 'Failed to import needed modules for type support:\n' + - traceback.format_exc()) - else: - cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__srv__custom_call__response - cls._CONVERT_FROM_PY = module.convert_from_py_msg__srv__custom_call__response - cls._CONVERT_TO_PY = module.convert_to_py_msg__srv__custom_call__response - cls._TYPE_SUPPORT = module.type_support_msg__srv__custom_call__response - cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__srv__custom_call__response - - @classmethod - def __prepare__(cls, name, bases, **kwargs): - # list constant names here so that they appear in the help text of - # the message class under "Data and other attributes defined here:" - # as well as populate each message instance - return { - } - - -class CustomCall_Response(_bases.CustomCall_ResponseBase, metaclass=Metaclass_CustomCall_Response): - """Message class 'CustomCall_Response'.""" - - # This field is modified after class creation. - # See the comment to Metaclass_CustomCall_Response.__new__ - __slots__ = [] - - _fields_and_field_types = { - 'my_result': 'int32', - } - - SLOT_TYPES = ( - rosidl_parser.definition.BasicType('int32'), # noqa: E501 - ) - - 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__)) - self.my_result = kwargs.get('my_result', int()) - - def __repr__(self): - typename = self.__class__.__module__.split('.') - typename.pop() - typename.append(self.__class__.__name__) - args = [] - for s, t in zip(self.__slots__, self.SLOT_TYPES): - field = getattr(self, s) - fieldstr = repr(field) - # We use Python array type for fields that can be directly stored - # in them, and "normal" sequences for everything else. If it is - # a type that we store in an array, strip off the 'array' portion. - if ( - isinstance(t, rosidl_parser.definition.AbstractSequence) and - isinstance(t.value_type, rosidl_parser.definition.BasicType) and - t.value_type.typename in ['float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] - ): - if len(field) == 0: - fieldstr = '[]' - else: - assert fieldstr.startswith('array(') - prefix = "array('X', " - suffix = ')' - fieldstr = fieldstr[len(prefix):-len(suffix)] - args.append(s[1:] + '=' + fieldstr) - return '%s(%s)' % ('.'.join(typename), ', '.join(args)) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - if self.my_result != other.my_result: - return False - return True - - @classmethod - def get_fields_and_field_types(cls): - from copy import copy - return copy(cls._fields_and_field_types) - - @builtins.property - def my_result(self): - """Message field 'my_result'.""" - return self._my_result - - @my_result.setter - def my_result(self, value): - if __debug__: - assert \ - isinstance(value, int), \ - "The 'my_result' field must be of type 'int'" - assert value >= -2147483648 and value < 2147483648, \ - "The 'my_result' field must be an integer in [-2147483648, 2147483647]" - self._my_result = value - - -# Import statements for member types - -# already imported above -# import builtins - -# already imported above -# import example_msgs._example_msgs_bases as _bases - -# already imported above -# import rosidl_parser.definition - - -class Metaclass_CustomCall_Event(type): - """Metaclass of message 'CustomCall_Event'.""" - - _CREATE_ROS_MESSAGE = None - _CONVERT_FROM_PY = None - _CONVERT_TO_PY = None - _DESTROY_ROS_MESSAGE = None - _TYPE_SUPPORT = None - - __constants = { - } - - def __new__(cls, *args): - new_type = super().__new__(cls, *args) - - # Ugly hack here. - # There are two purposes for __slots__ field of message class: - # 1) __slots__ field is used in ROS as a list of message members. - # Number of ROS packages rely on its value. - # 2) defining __slots__ in Python class prevents adding __dict__ - # to class instances. This behvior is desirable. - # If #1 defined in message class body, then base class member descriptors are - # overriden and no longer can be used. On the other side, any __slots__ value - # should be defined to guaratee #2. - # So we define empty list in message class body and modify it after type object - # constructed. This is neither prohibited, nor encouraged by CPython documentation. - new_type.__slots__ += [ - '_info', - '_request', - '_response', - ] - return new_type - - @classmethod - def __import_type_support__(cls): - try: - from rosidl_generator_py import import_type_support - module = import_type_support('example_msgs') - except ImportError: - import logging - import traceback - logger = logging.getLogger( - 'example_msgs.srv.CustomCall_Event') - logger.debug( - 'Failed to import needed modules for type support:\n' + - traceback.format_exc()) - else: - cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__srv__custom_call__event - cls._CONVERT_FROM_PY = module.convert_from_py_msg__srv__custom_call__event - cls._CONVERT_TO_PY = module.convert_to_py_msg__srv__custom_call__event - cls._TYPE_SUPPORT = module.type_support_msg__srv__custom_call__event - cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__srv__custom_call__event - - from service_msgs.msg import ServiceEventInfo - if ServiceEventInfo.__class__._TYPE_SUPPORT is None: - ServiceEventInfo.__class__.__import_type_support__() - - @classmethod - def __prepare__(cls, name, bases, **kwargs): - # list constant names here so that they appear in the help text of - # the message class under "Data and other attributes defined here:" - # as well as populate each message instance - return { - } - - -class CustomCall_Event(_bases.CustomCall_EventBase, metaclass=Metaclass_CustomCall_Event): - """Message class 'CustomCall_Event'.""" - - # This field is modified after class creation. - # See the comment to Metaclass_CustomCall_Event.__new__ - __slots__ = [] - - _fields_and_field_types = { - 'info': 'service_msgs/ServiceEventInfo', - 'request': 'sequence', - 'response': 'sequence', - } - - SLOT_TYPES = ( - rosidl_parser.definition.NamespacedType(['service_msgs', 'msg'], 'ServiceEventInfo'), # noqa: E501 - rosidl_parser.definition.BoundedSequence(rosidl_parser.definition.NamespacedType(['example_msgs', 'srv'], 'CustomCall_Request'), 1), # noqa: E501 - rosidl_parser.definition.BoundedSequence(rosidl_parser.definition.NamespacedType(['example_msgs', 'srv'], 'CustomCall_Response'), 1), # noqa: E501 - ) - - 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__)) - from service_msgs.msg import ServiceEventInfo - self.info = kwargs.get('info', ServiceEventInfo()) - self.request = kwargs.get('request', []) - self.response = kwargs.get('response', []) - - def __repr__(self): - typename = self.__class__.__module__.split('.') - typename.pop() - typename.append(self.__class__.__name__) - args = [] - for s, t in zip(self.__slots__, self.SLOT_TYPES): - field = getattr(self, s) - fieldstr = repr(field) - # We use Python array type for fields that can be directly stored - # in them, and "normal" sequences for everything else. If it is - # a type that we store in an array, strip off the 'array' portion. - if ( - isinstance(t, rosidl_parser.definition.AbstractSequence) and - isinstance(t.value_type, rosidl_parser.definition.BasicType) and - t.value_type.typename in ['float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] - ): - if len(field) == 0: - fieldstr = '[]' - else: - assert fieldstr.startswith('array(') - prefix = "array('X', " - suffix = ')' - fieldstr = fieldstr[len(prefix):-len(suffix)] - args.append(s[1:] + '=' + fieldstr) - return '%s(%s)' % ('.'.join(typename), ', '.join(args)) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - if self.info != other.info: - return False - if self.request != other.request: - return False - if self.response != other.response: - return False - return True - - @classmethod - def get_fields_and_field_types(cls): - from copy import copy - return copy(cls._fields_and_field_types) - - @builtins.property - def info(self): - """Message field 'info'.""" - return self._info - - @info.setter - def info(self, value): - if __debug__: - from service_msgs.msg import ServiceEventInfo - assert \ - isinstance(value, ServiceEventInfo), \ - "The 'info' field must be a sub message of type 'ServiceEventInfo'" - self._info = value - - @builtins.property - def request(self): - """Message field 'request'.""" - return self._request - - @request.setter - def request(self, value): - if __debug__: - from example_msgs.srv import CustomCall_Request - from collections.abc import Sequence - from collections.abc import Set - from collections import UserList - from collections import UserString - assert \ - ((isinstance(value, Sequence) or - isinstance(value, Set) or - isinstance(value, UserList)) and - not isinstance(value, str) and - not isinstance(value, UserString) and - len(value) <= 1 and - all(isinstance(v, CustomCall_Request) for v in value) and - True), \ - "The 'request' field must be a set or sequence with length <= 1 and each value of type 'CustomCall_Request'" - self._request = value - - @builtins.property - def response(self): - """Message field 'response'.""" - return self._response - - @response.setter - def response(self, value): - if __debug__: - from example_msgs.srv import CustomCall_Response - from collections.abc import Sequence - from collections.abc import Set - from collections import UserList - from collections import UserString - assert \ - ((isinstance(value, Sequence) or - isinstance(value, Set) or - isinstance(value, UserList)) and - not isinstance(value, str) and - not isinstance(value, UserString) and - len(value) <= 1 and - all(isinstance(v, CustomCall_Response) for v in value) and - True), \ - "The 'response' field must be a set or sequence with length <= 1 and each value of type 'CustomCall_Response'" - self._response = value - - -class Metaclass_CustomCall(type): - """Metaclass of service 'CustomCall'.""" - - _TYPE_SUPPORT = None - - @classmethod - def __import_type_support__(cls): - try: - from rosidl_generator_py import import_type_support - module = import_type_support('example_msgs') - except ImportError: - import logging - import traceback - logger = logging.getLogger( - 'example_msgs.srv.CustomCall') - logger.debug( - 'Failed to import needed modules for type support:\n' + - traceback.format_exc()) - else: - cls._TYPE_SUPPORT = module.type_support_srv__srv__custom_call - - from example_msgs.srv import _custom_call - if _custom_call.Metaclass_CustomCall_Request._TYPE_SUPPORT is None: - _custom_call.Metaclass_CustomCall_Request.__import_type_support__() - if _custom_call.Metaclass_CustomCall_Response._TYPE_SUPPORT is None: - _custom_call.Metaclass_CustomCall_Response.__import_type_support__() - if _custom_call.Metaclass_CustomCall_Event._TYPE_SUPPORT is None: - _custom_call.Metaclass_CustomCall_Event.__import_type_support__() - - -class CustomCall(metaclass=Metaclass_CustomCall): - from example_msgs.srv._custom_call import CustomCall_Request as Request - from example_msgs.srv._custom_call import CustomCall_Response as Response - from example_msgs.srv._custom_call import CustomCall_Event as Event - - def __init__(self): - raise NotImplementedError('Service classes can not be instantiated') diff --git a/rosidl_generator_py/example/srv/_custom_call_s.c b/rosidl_generator_py/example/srv/_custom_call_s.c deleted file mode 100644 index 7b5c506d..00000000 --- a/rosidl_generator_py/example/srv/_custom_call_s.c +++ /dev/null @@ -1,332 +0,0 @@ -// generated from rosidl_generator_py/resource/_idl_support.c.em -// with input from example_msgs:srv/CustomCall.idl -// generated code does not contain a copyright notice -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#include -#include -#ifndef _WIN32 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-function" -#endif -#include "numpy/ndarrayobject.h" -#ifndef _WIN32 -# pragma GCC diagnostic pop -#endif -#include "rosidl_runtime_c/visibility_control.h" -#include "example_msgs/srv/detail/custom_call__struct.h" -#include "example_msgs/srv/detail/custom_call__functions.h" -#include "../_example_msgs_decl.h" - - -ROSIDL_GENERATOR_C_EXPORT -bool example_msgs__srv__custom_call__request__convert_from_py(PyObject * _pymsg, void * _ros_message) -{ - // check that the passed message is of the expected Python class - { - PyTypeObject * py_type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__REQUEST__IMPORT_INDEX); - assert(Py_TYPE(_pymsg) == py_type); - } - example_msgs__srv__CustomCall_Request * ros_message = _ros_message; - - CustomCall_RequestBase * base_msg = (CustomCall_RequestBase *)_pymsg; - { // my_param - ros_message->my_param = base_msg->_my_param; - } - - return true; -} - -ROSIDL_GENERATOR_C_EXPORT -PyObject * example_msgs__srv__custom_call__request__convert_to_py(void * raw_ros_message) -{ - /* NOTE(esteve): Call constructor of CustomCall_Request */ - CustomCall_RequestBase * _pymessage = NULL; - { - PyTypeObject * type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__REQUEST__IMPORT_INDEX); - if (!type) { - return NULL; - } - assert(type->tp_new); - - PyObject * empty_tuple = PyTuple_New(0); - if (!empty_tuple) { - return NULL; - } - - _pymessage = (CustomCall_RequestBase *)type->tp_new(type, empty_tuple, NULL); - Py_DECREF(empty_tuple); - if (!_pymessage) { - return NULL; - } - } - example_msgs__srv__CustomCall_Request * ros_message = (example_msgs__srv__CustomCall_Request *)raw_ros_message; - { // my_param - _pymessage->_my_param = ros_message->my_param; - } - - // ownership of _pymessage is transferred to the caller - return (PyObject *)_pymessage; -} - -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -// already included above -// #include -// already included above -// #include -// already included above -// #include "numpy/ndarrayobject.h" -// already included above -// #include "rosidl_runtime_c/visibility_control.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__struct.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__functions.h" -// already included above -// #include "../_example_msgs_decl.h" - - -ROSIDL_GENERATOR_C_EXPORT -bool example_msgs__srv__custom_call__response__convert_from_py(PyObject * _pymsg, void * _ros_message) -{ - // check that the passed message is of the expected Python class - { - PyTypeObject * py_type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__RESPONSE__IMPORT_INDEX); - assert(Py_TYPE(_pymsg) == py_type); - } - example_msgs__srv__CustomCall_Response * ros_message = _ros_message; - - CustomCall_ResponseBase * base_msg = (CustomCall_ResponseBase *)_pymsg; - { // my_result - ros_message->my_result = base_msg->_my_result; - } - - return true; -} - -ROSIDL_GENERATOR_C_EXPORT -PyObject * example_msgs__srv__custom_call__response__convert_to_py(void * raw_ros_message) -{ - /* NOTE(esteve): Call constructor of CustomCall_Response */ - CustomCall_ResponseBase * _pymessage = NULL; - { - PyTypeObject * type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__RESPONSE__IMPORT_INDEX); - if (!type) { - return NULL; - } - assert(type->tp_new); - - PyObject * empty_tuple = PyTuple_New(0); - if (!empty_tuple) { - return NULL; - } - - _pymessage = (CustomCall_ResponseBase *)type->tp_new(type, empty_tuple, NULL); - Py_DECREF(empty_tuple); - if (!_pymessage) { - return NULL; - } - } - example_msgs__srv__CustomCall_Response * ros_message = (example_msgs__srv__CustomCall_Response *)raw_ros_message; - { // my_result - _pymessage->_my_result = ros_message->my_result; - } - - // ownership of _pymessage is transferred to the caller - return (PyObject *)_pymessage; -} - -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -// already included above -// #include -// already included above -// #include -// already included above -// #include "numpy/ndarrayobject.h" -// already included above -// #include "rosidl_runtime_c/visibility_control.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__struct.h" -// already included above -// #include "example_msgs/srv/detail/custom_call__functions.h" -// already included above -// #include "../_example_msgs_decl.h" - -#include "rosidl_runtime_c/primitives_sequence.h" -#include "rosidl_runtime_c/primitives_sequence_functions.h" - -// Nested array functions includes - - -// end nested array functions include -ROSIDL_GENERATOR_C_IMPORT -bool service_msgs__msg__service_event_info__convert_from_py(PyObject * _pymsg, void * _ros_message); -ROSIDL_GENERATOR_C_IMPORT -PyObject * service_msgs__msg__service_event_info__convert_to_py(void * raw_ros_message); -bool example_msgs__srv__custom_call__request__convert_from_py(PyObject * _pymsg, void * _ros_message); -PyObject * example_msgs__srv__custom_call__request__convert_to_py(void * raw_ros_message); -bool example_msgs__srv__custom_call__response__convert_from_py(PyObject * _pymsg, void * _ros_message); -PyObject * example_msgs__srv__custom_call__response__convert_to_py(void * raw_ros_message); - -ROSIDL_GENERATOR_C_EXPORT -bool example_msgs__srv__custom_call__event__convert_from_py(PyObject * _pymsg, void * _ros_message) -{ - // check that the passed message is of the expected Python class - { - PyTypeObject * py_type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__EVENT__IMPORT_INDEX); - assert(Py_TYPE(_pymsg) == py_type); - } - example_msgs__srv__CustomCall_Event * ros_message = _ros_message; - - CustomCall_EventBase * base_msg = (CustomCall_EventBase *)_pymsg; - { // info - PyObject * field = base_msg->_info; - if (!field) { - return false; - } - if (!service_msgs__msg__service_event_info__convert_from_py(field, &ros_message->info)) { - return false; - } - } - { // request - PyObject * field = base_msg->_request; - if (!field) { - return false; - } - PyObject * seq_field = PySequence_Fast(field, "expected a sequence in 'request'"); - if (!seq_field) { - return false; - } - Py_ssize_t size = PySequence_Size(field); - if (-1 == size) { - Py_DECREF(seq_field); - return false; - } - if (!example_msgs__srv__CustomCall_Request__Sequence__init(&(ros_message->request), size)) { - PyErr_SetString(PyExc_RuntimeError, "unable to create example_msgs__srv__CustomCall_Request__Sequence ros_message"); - Py_DECREF(seq_field); - return false; - } - example_msgs__srv__CustomCall_Request * dest = ros_message->request.data; - for (Py_ssize_t i = 0; i < size; ++i) { - if (!example_msgs__srv__custom_call__request__convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) { - Py_DECREF(seq_field); - return false; - } - } - Py_DECREF(seq_field); - } - { // response - PyObject * field = base_msg->_response; - if (!field) { - return false; - } - PyObject * seq_field = PySequence_Fast(field, "expected a sequence in 'response'"); - if (!seq_field) { - return false; - } - Py_ssize_t size = PySequence_Size(field); - if (-1 == size) { - Py_DECREF(seq_field); - return false; - } - if (!example_msgs__srv__CustomCall_Response__Sequence__init(&(ros_message->response), size)) { - PyErr_SetString(PyExc_RuntimeError, "unable to create example_msgs__srv__CustomCall_Response__Sequence ros_message"); - Py_DECREF(seq_field); - return false; - } - example_msgs__srv__CustomCall_Response * dest = ros_message->response.data; - for (Py_ssize_t i = 0; i < size; ++i) { - if (!example_msgs__srv__custom_call__response__convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) { - Py_DECREF(seq_field); - return false; - } - } - Py_DECREF(seq_field); - } - - return true; -} - -ROSIDL_GENERATOR_C_EXPORT -PyObject * example_msgs__srv__custom_call__event__convert_to_py(void * raw_ros_message) -{ - /* NOTE(esteve): Call constructor of CustomCall_Event */ - CustomCall_EventBase * _pymessage = NULL; - { - PyTypeObject * type = (PyTypeObject *)example_msgs__lazy_import(NULL, EXAMPLE_MSGS__SRV__CUSTOM_CALL__EVENT__IMPORT_INDEX); - if (!type) { - return NULL; - } - assert(type->tp_new); - - PyObject * empty_tuple = PyTuple_New(0); - if (!empty_tuple) { - return NULL; - } - - _pymessage = (CustomCall_EventBase *)type->tp_new(type, empty_tuple, NULL); - Py_DECREF(empty_tuple); - if (!_pymessage) { - return NULL; - } - } - example_msgs__srv__CustomCall_Event * ros_message = (example_msgs__srv__CustomCall_Event *)raw_ros_message; - { // info - PyObject * field = NULL; - field = service_msgs__msg__service_event_info__convert_to_py(&ros_message->info); - if (!field) { - return NULL; - } - // reference is transfered to object - _pymessage->_info = field; - } - { // request - PyObject * field = NULL; - size_t size = ros_message->request.size; - field = PyList_New(size); - if (!field) { - return NULL; - } - example_msgs__srv__CustomCall_Request * item; - for (size_t i = 0; i < size; ++i) { - item = &(ros_message->request.data[i]); - PyObject * pyitem = example_msgs__srv__custom_call__request__convert_to_py(item); - if (!pyitem) { - Py_DECREF(field); - return NULL; - } - int rc = PyList_SetItem(field, i, pyitem); - (void)rc; - assert(rc == 0); - } - assert(PySequence_Check(field)); - // reference is transfered to object - _pymessage->_request = field; - } - { // response - PyObject * field = NULL; - size_t size = ros_message->response.size; - field = PyList_New(size); - if (!field) { - return NULL; - } - example_msgs__srv__CustomCall_Response * item; - for (size_t i = 0; i < size; ++i) { - item = &(ros_message->response.data[i]); - PyObject * pyitem = example_msgs__srv__custom_call__response__convert_to_py(item); - if (!pyitem) { - Py_DECREF(field); - return NULL; - } - int rc = PyList_SetItem(field, i, pyitem); - (void)rc; - assert(rc == 0); - } - assert(PySequence_Check(field)); - // reference is transfered to object - _pymessage->_response = field; - } - - // ownership of _pymessage is transferred to the caller - return (PyObject *)_pymessage; -}