3030_IS_SYNC = False
3131
3232
33- def _make_executor (interval = 30.0 , min_interval = 0.01 , target = None , name = "test" ):
34- if target is None :
33+ class TestAsyncPeriodicExecutor (AsyncUnitTest ):
34+ def _make_executor (self , interval = 30.0 , min_interval = 0.01 , target = None , name = "test" ):
35+ if target is None :
3536
36- async def target ():
37- return True
38-
39- return AsyncPeriodicExecutor (
40- interval = interval , min_interval = min_interval , target = target , name = name
41- )
42-
43-
44- class AsyncPeriodicExecutorTestBase (AsyncUnitTest ):
45- async def asyncSetUp (self ):
46- self .executor = None
47-
48- async def asyncTearDown (self ):
49- if self .executor is not None :
50- self .executor .close ()
51- await self .executor .join (timeout = 2 )
37+ async def target ():
38+ return True
5239
40+ executor = AsyncPeriodicExecutor (
41+ interval = interval , min_interval = min_interval , target = target , name = name
42+ )
43+ self .addAsyncCleanup (self ._close_executor , executor )
44+ return executor
5345
54- class TestAsyncPeriodicExecutor (AsyncPeriodicExecutorTestBase ):
55- async def test_repr_contains_class_and_name (self ):
56- executor = _make_executor (name = "exec" )
57- executor_repr = repr (executor )
58- self .assertIn ("AsyncPeriodicExecutor" , executor_repr )
59- self .assertIn ("exec" , executor_repr )
46+ async def _close_executor (self , executor ):
47+ executor .close ()
48+ await executor .join (timeout = 2 )
6049
6150 async def test_join_without_open_is_safe (self ):
62- self . executor = _make_executor ()
51+ executor = self . _make_executor ()
6352 try :
64- await self . executor .join (timeout = 0.01 )
53+ await executor .join (timeout = 0.01 )
6554 except Exception as e :
6655 self .fail (f"join() raised unexpected Exception { e } " )
6756
@@ -75,47 +64,25 @@ async def target():
7564 ran .set ()
7665 return False
7766
78- self . executor = _make_executor (target = target )
79- self . executor .open ()
80- await self . executor .join (timeout = 2 )
67+ executor = self . _make_executor (target = target )
68+ executor .open ()
69+ await executor .join (timeout = 2 )
8170 self .assertTrue (ran .is_set (), "target never ran" )
8271
8372 async def test_target_exception_stops_executor (self ):
84- if _IS_SYNC :
85- ran = threading .Event ()
86- captured_exc : list = []
87- orig_excepthook = threading .excepthook
88-
89- def _capture_excepthook (args ):
90- captured_exc .append (args .exc_value )
91-
92- threading .excepthook = _capture_excepthook
93- try :
94-
95- def target ():
96- ran .set ()
97- raise RuntimeError ("error" )
98-
99- self .executor = _make_executor (target = target )
100- self .executor .open ()
101- self .executor .join (timeout = 2 )
102- self .assertTrue (ran .is_set (), "target never ran" )
103- finally :
104- threading .excepthook = orig_excepthook
105- self .assertEqual (len (captured_exc ), 1 )
106- self .assertIsInstance (captured_exc [0 ], RuntimeError )
107- else :
108- call_count = 0
73+ call_count = 0
10974
110- async def target ():
111- nonlocal call_count
112- call_count += 1
113- raise RuntimeError ("error" )
75+ async def target ():
76+ nonlocal call_count
77+ call_count += 1
78+ raise RuntimeError ("error" )
11479
115- self .executor = _make_executor (target = target )
116- self .executor .open ()
117- await self .executor .join (timeout = 2 )
118- self .assertEqual (call_count , 1 , "target should stop after exception" )
80+ executor = self ._make_executor (target = target )
81+ executor .open ()
82+ await executor .join (timeout = 2 )
83+ if executor ._task is not None and executor ._task .done ():
84+ executor ._task .exception ()
85+ self .assertEqual (call_count , 1 , "target should stop after exception" )
11986
12087 async def test_skip_sleep_flag_skips_interval (self ):
12188 call_times = []
@@ -126,10 +93,10 @@ async def target():
12693 return False
12794 return True
12895
129- self . executor = _make_executor (interval = 30.0 , min_interval = 0.001 , target = target )
130- self . executor .skip_sleep ()
131- self . executor .open ()
132- await self . executor .join (timeout = 3 )
96+ executor = self . _make_executor (interval = 30.0 , min_interval = 0.001 , target = target )
97+ executor .skip_sleep ()
98+ executor .open ()
99+ await executor .join (timeout = 3 )
133100 self .assertGreaterEqual (len (call_times ), 2 )
134101 self .assertLess (call_times [1 ] - call_times [0 ], 5.0 )
135102
@@ -147,15 +114,15 @@ async def target():
147114 woken .set ()
148115 return call_count < 2
149116
150- self . executor = _make_executor (interval = 30.0 , min_interval = 0.01 , target = target )
151- self . executor .open ()
117+ executor = self . _make_executor (interval = 30.0 , min_interval = 0.01 , target = target )
118+ executor .open ()
152119 if _IS_SYNC :
153120 woken .wait (timeout = 2 )
154121 else :
155122 assert isinstance (woken , asyncio .Event )
156123 await asyncio .wait_for (woken .wait (), timeout = 2 )
157- self . executor .wake ()
158- await self . executor .join (timeout = 3 )
124+ executor .wake ()
125+ await executor .join (timeout = 3 )
159126 self .assertGreaterEqual (call_count , 2 )
160127
161128 async def test_open_after_target_returns_false (self ):
@@ -166,11 +133,11 @@ async def target():
166133 called += 1
167134 return False
168135
169- self . executor = _make_executor (target = target )
170- self . executor .open ()
171- await self . executor .join (timeout = 2 )
172- self . executor .open ()
173- await self . executor .join (timeout = 2 )
136+ executor = self . _make_executor (target = target )
137+ executor .open ()
138+ await executor .join (timeout = 2 )
139+ executor .open ()
140+ await executor .join (timeout = 2 )
174141 self .assertGreaterEqual (called , 2 )
175142
176143
0 commit comments