diff --git a/rclpy/CMakeLists.txt b/rclpy/CMakeLists.txt index de713387f..c52b7c0ba 100644 --- a/rclpy/CMakeLists.txt +++ b/rclpy/CMakeLists.txt @@ -26,19 +26,16 @@ if(WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Debug") set(PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE_DEBUG}") endif() -# enables using the Python package from the source space -# This creates a folder in ${CMAKE_CURRENT_BINARY_DIR}/rclpy which has all the -# as well as the compiled modules from the build space -# necessary Python code and C Python extensions for running tests. -configure_file("__init__.py.in" "rclpy/__init__.py" @ONLY) +# enables using the Python extensions from the build space for testing +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_rclpy/__init__.py" "") ament_python_install_package(${PROJECT_NAME}) function(set_properties _targetname _build_type) set_target_properties(${_targetname} PROPERTIES PREFIX "" - LIBRARY_OUTPUT_DIRECTORY${_build_type} "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}" - RUNTIME_OUTPUT_DIRECTORY${_build_type} "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}" + LIBRARY_OUTPUT_DIRECTORY${_build_type} "${CMAKE_CURRENT_BINARY_DIR}/test_${PROJECT_NAME}" + RUNTIME_OUTPUT_DIRECTORY${_build_type} "${CMAKE_CURRENT_BINARY_DIR}/test_${PROJECT_NAME}" OUTPUT_NAME "_${_targetname}${PythonExtra_EXTENSION_SUFFIX}" SUFFIX "${PythonExtra_EXTENSION_EXTENSION}") endfunction() @@ -109,9 +106,9 @@ if(BUILD_TESTING) endif() if(NOT _typesupport_impls STREQUAL "") ament_add_pytest_test(rclpytests test - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}" APPEND_ENV AMENT_PREFIX_PATH=${ament_index_build_path} + PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR} TIMEOUT 90 ) endif() diff --git a/rclpy/__init__.py.in b/rclpy/__init__.py.in deleted file mode 100644 index e64ea1ba7..000000000 --- a/rclpy/__init__.py.in +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# generated from rclpy/__init__.py.in -# keep symbol table as clean as possible by deleting all unnecessary symbols - -from os import path as os_path -from pkgutil import extend_path -from sys import path as sys_path - -source_path = '@CMAKE_CURRENT_SOURCE_DIR@' -sys_path.insert(0, source_path) -del sys_path - -__path__ = extend_path(__path__, __name__) -del extend_path - -__execfiles = [] -src_init_file = os_path.join(source_path, __name__ + '.py') -if os_path.isfile(src_init_file): - __execfiles.append(src_init_file) -else: - src_init_file = os_path.join(source_path, __name__, '__init__.py') - if os_path.isfile(src_init_file): - __execfiles.append(src_init_file) -del os_path -del src_init_file -del source_path - -for __execfile in __execfiles: - with open(__execfile, 'r') as __fh: - __code_object = compile(__fh.read(), __execfile, 'exec') - exec(__code_object) - del __code_object - del __fh - del __execfile -del __execfiles diff --git a/rclpy/rclpy/__init__.py b/rclpy/rclpy/__init__.py index 9b05ecba6..0569e8228 100644 --- a/rclpy/rclpy/__init__.py +++ b/rclpy/rclpy/__init__.py @@ -14,9 +14,6 @@ import sys -from rclpy.executors import SingleThreadedExecutor as _SingleThreadedExecutor -from rclpy.impl.implementation_singleton import rclpy_implementation as _rclpy -from rclpy.node import Node from rclpy.utilities import get_rmw_implementation_identifier # noqa from rclpy.utilities import ok from rclpy.utilities import shutdown # noqa @@ -24,15 +21,22 @@ def init(*, args=None): - return _rclpy.rclpy_init(args if args is not None else sys.argv) + # imported locally to avoid loading extensions on module import + from rclpy.impl.implementation_singleton import rclpy_implementation + return rclpy_implementation.rclpy_init( + args if args is not None else sys.argv) def create_node(node_name, *, namespace=None): + # imported locally to avoid loading extensions on module import + from rclpy.node import Node return Node(node_name, namespace=namespace) def spin_once(node, *, timeout_sec=None): - executor = _SingleThreadedExecutor() + # imported locally to avoid loading extensions on module import + from rclpy.executors import SingleThreadedExecutor + executor = SingleThreadedExecutor() try: executor.add_node(node) executor.spin_once(timeout_sec=timeout_sec) @@ -41,7 +45,9 @@ def spin_once(node, *, timeout_sec=None): def spin(node): - executor = _SingleThreadedExecutor() + # imported locally to avoid loading extensions on module import + from rclpy.executors import SingleThreadedExecutor + executor = SingleThreadedExecutor() try: executor.add_node(node) while ok(): diff --git a/rclpy/rclpy/impl/__init__.py b/rclpy/rclpy/impl/__init__.py index e69de29bb..da56aee2f 100644 --- a/rclpy/rclpy/impl/__init__.py +++ b/rclpy/rclpy/impl/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2016-2017 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import importlib +import os + + +def _import(name): + try: + return importlib.import_module(name, package='rclpy') + except ImportError as e: + if e.path is not None and os.path.isfile(e.path): + e.msg += \ + "\nThe C extension '%s' failed to be imported while being present on the system." \ + " Please refer to '%s' for possible solutions" % \ + (e.path, 'https://github.com/ros2/ros2/wiki/Rclpy-Import-error-hint') + raise diff --git a/rclpy/rclpy/impl/implementation_singleton.py b/rclpy/rclpy/impl/implementation_singleton.py index 6551d0b22..1f984bd66 100644 --- a/rclpy/rclpy/impl/implementation_singleton.py +++ b/rclpy/rclpy/impl/implementation_singleton.py @@ -26,16 +26,7 @@ # ... """ -import importlib -import os +from rclpy.impl import _import -try: - rclpy_implementation = importlib.import_module('._rclpy', package='rclpy') - rclpy_logging_implementation = importlib.import_module('._rclpy_logging', package='rclpy') -except ImportError as e: - if e.path is not None and os.path.isfile(e.path): - e.msg += \ - "\nThe C extension '%s' failed to be imported while being present on the system." \ - " Please refer to '%s' for possible solutions" % \ - (e.path, 'https://github.com/ros2/ros2/wiki/Rclpy-Import-error-hint') - raise +rclpy_implementation = _import('._rclpy') +rclpy_logging_implementation = _import('._rclpy_logging') diff --git a/rclpy/rclpy/utilities.py b/rclpy/rclpy/utilities.py index 00de43212..58141481e 100644 --- a/rclpy/rclpy/utilities.py +++ b/rclpy/rclpy/utilities.py @@ -14,27 +14,33 @@ import threading -from rclpy.impl.implementation_singleton import rclpy_implementation as _rclpy - g_shutdown_lock = threading.Lock() def ok(): + # imported locally to avoid loading extensions on module import + from rclpy.impl.implementation_singleton import rclpy_implementation with g_shutdown_lock: - return _rclpy.rclpy_ok() + return rclpy_implementation.rclpy_ok() def shutdown(): + # imported locally to avoid loading extensions on module import + from rclpy.impl.implementation_singleton import rclpy_implementation with g_shutdown_lock: - return _rclpy.rclpy_shutdown() + return rclpy_implementation.rclpy_shutdown() def try_shutdown(): """Shutdown rclpy if not already shutdown.""" + # imported locally to avoid loading extensions on module import + from rclpy.impl.implementation_singleton import rclpy_implementation with g_shutdown_lock: - if _rclpy.rclpy_ok(): - return _rclpy.rclpy_shutdown() + if rclpy_implementation.rclpy_ok(): + return rclpy_implementation.rclpy_shutdown() def get_rmw_implementation_identifier(): - return _rclpy.rclpy_get_rmw_implementation_identifier() + # imported locally to avoid loading extensions on module import + from rclpy.impl.implementation_singleton import rclpy_implementation + return rclpy_implementation.rclpy_get_rmw_implementation_identifier() diff --git a/rclpy/test/__init__.py b/rclpy/test/__init__.py index 22c381697..8f1a3098a 100644 --- a/rclpy/test/__init__.py +++ b/rclpy/test/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2016 Open Source Robotics Foundation, Inc. +# Copyright 2016-2017 Open Source Robotics Foundation, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,11 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os +import importlib import sys assert 'rclpy' not in sys.modules, 'rclpy should not have been imported before running tests' -sys.path.insert(0, os.getcwd()) -import rclpy # noqa -assert rclpy # silence pyflakes +# this will make the extensions load from the build folder +import rclpy.impl # noqa +import test_rclpy # noqa + + +def _custom_import(name): + return importlib.import_module(name, package='test_rclpy') + + +rclpy.impl._import = _custom_import