@@ -192,7 +192,12 @@ cdef class TimerHandle:
192
192
self .context = None
193
193
194
194
if loop._debug:
195
- self ._source_traceback = extract_stack()
195
+ self ._debug_info = (
196
+ format_callback_name(callback),
197
+ extract_stack()
198
+ )
199
+ else :
200
+ self ._debug_info = None
196
201
197
202
self .timer = UVTimer.new(
198
203
loop, < method_t> self ._run, self , delay)
@@ -202,6 +207,11 @@ cdef class TimerHandle:
202
207
# Only add to loop._timers when `self.timer` is successfully created
203
208
loop._timers.add(self )
204
209
210
+ property _source_traceback :
211
+ def __get__ (self ):
212
+ if self ._debug_info is not None :
213
+ return self ._debug_info[1 ]
214
+
205
215
def __dealloc__ (self ):
206
216
if UVLOOP_DEBUG:
207
217
self .loop._debug_cb_timer_handles_count -= 1
@@ -225,7 +235,7 @@ cdef class TimerHandle:
225
235
self .loop._timers.remove(self )
226
236
finally :
227
237
self .timer._close()
228
- self .timer = None # let it die asap
238
+ self .timer = None # let the UVTimer handle GC
229
239
230
240
cdef _run(self ):
231
241
if self ._cancelled == 1 :
@@ -256,8 +266,8 @@ cdef class TimerHandle:
256
266
' handle' : self ,
257
267
}
258
268
259
- if self ._source_traceback is not None :
260
- context[' source_traceback' ] = self ._source_traceback
269
+ if self ._debug_info is not None :
270
+ context[' source_traceback' ] = self ._debug_info[ 1 ]
261
271
262
272
self .loop.call_exception_handler(context)
263
273
else :
@@ -272,6 +282,7 @@ cdef class TimerHandle:
272
282
Py_DECREF(self )
273
283
if PY37:
274
284
Context_Exit(context)
285
+ self ._clear()
275
286
276
287
# Public API
277
288
@@ -281,19 +292,20 @@ cdef class TimerHandle:
281
292
if self ._cancelled:
282
293
info.append(' cancelled' )
283
294
284
- if self .callback is not None :
285
- func = self .callback
286
- if hasattr (func, ' __qualname__' ):
287
- cb_name = getattr (func, ' __qualname__' )
288
- elif hasattr (func, ' __name__' ):
289
- cb_name = getattr (func, ' __name__' )
290
- else :
291
- cb_name = repr (func)
295
+ if self ._debug_info is not None :
296
+ callback_name = self ._debug_info[0 ]
297
+ source_traceback = self ._debug_info[1 ]
298
+ else :
299
+ callback_name = None
300
+ source_traceback = None
292
301
293
- info.append(cb_name)
302
+ if callback_name is not None :
303
+ info.append(callback_name)
304
+ elif self .callback is not None :
305
+ info.append(format_callback_name(self .callback))
294
306
295
- if self ._source_traceback is not None :
296
- frame = self ._source_traceback [- 1 ]
307
+ if source_traceback is not None :
308
+ frame = source_traceback [- 1 ]
297
309
info.append(' created at {}:{}' .format(frame[0 ], frame[1 ]))
298
310
299
311
return ' <' + ' ' .join(info) + ' >'
@@ -305,6 +317,15 @@ cdef class TimerHandle:
305
317
self ._cancel()
306
318
307
319
320
+ cdef format_callback_name(func):
321
+ if hasattr (func, ' __qualname__' ):
322
+ cb_name = getattr (func, ' __qualname__' )
323
+ elif hasattr (func, ' __name__' ):
324
+ cb_name = getattr (func, ' __name__' )
325
+ else :
326
+ cb_name = repr (func)
327
+ return cb_name
328
+
308
329
309
330
cdef new_Handle(Loop loop, object callback, object args, object context):
310
331
cdef Handle handle
0 commit comments