From 8db266a79331f8b97f836c9ca963b8e0d647b457 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 5 Jun 2024 04:06:01 -0400 Subject: [PATCH] Make timers context-aware. (#1296) This should make it easier to create examples and demos that properly clean up after themselves. Signed-off-by: Chris Lalancette --- rclpy/rclpy/timer.py | 13 +++++++++++++ rclpy/test/test_timer.py | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/rclpy/rclpy/timer.py b/rclpy/rclpy/timer.py index 1a3024496..6f2480055 100644 --- a/rclpy/rclpy/timer.py +++ b/rclpy/rclpy/timer.py @@ -14,8 +14,10 @@ import threading +from types import TracebackType from typing import Callable from typing import Optional +from typing import Type from rclpy.callback_groups import CallbackGroup from rclpy.clock import Clock @@ -114,6 +116,17 @@ def time_until_next_call(self): with self.__timer: return self.__timer.time_until_next_call() + def __enter__(self) -> 'Timer': + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.destroy() + class Rate: """A utility for sleeping at a fixed rate.""" diff --git a/rclpy/test/test_timer.py b/rclpy/test/test_timer.py index 394f75036..f947a7738 100644 --- a/rclpy/test/test_timer.py +++ b/rclpy/test/test_timer.py @@ -202,3 +202,19 @@ def test_timer_without_autostart(): if node is not None: node.destroy_node() rclpy.shutdown() + + +def test_timer_context_manager(): + rclpy.init() + try: + with rclpy.create_node('test_timer_without_autostart') as node: + with node.create_timer(1, lambda: None, autostart=False) as timer: + assert timer.is_canceled() + + timer.reset() + assert not timer.is_canceled() + + timer.cancel() + assert timer.is_canceled() + finally: + rclpy.shutdown()