@@ -189,66 +189,75 @@ def iscoroutine(obj):
189
189
def _format_coroutine (coro ):
190
190
assert iscoroutine (coro )
191
191
192
- if not hasattr (coro , 'cr_code' ) and not hasattr (coro , 'gi_code' ):
193
- # Most likely a built-in type or a Cython coroutine.
194
-
195
- # Built-in types might not have __qualname__ or __name__.
196
- coro_name = getattr (
197
- coro , '__qualname__' ,
198
- getattr (coro , '__name__' , type (coro ).__name__ ))
199
- coro_name = f'{ coro_name } ()'
192
+ is_corowrapper = isinstance (coro , CoroWrapper )
193
+
194
+ def get_name (coro ):
195
+ # Coroutines compiled with Cython sometimes don't have
196
+ # proper __qualname__ or __name__. While that is a bug
197
+ # in Cython, asyncio shouldn't crash with an AttributeError
198
+ # in its __repr__ functions.
199
+ if is_corowrapper :
200
+ return format_helpers ._format_callback (coro .func , (), {})
201
+
202
+ if hasattr (coro , '__qualname__' ) and coro .__qualname__ :
203
+ coro_name = coro .__qualname__
204
+ elif hasattr (coro , '__name__' ) and coro .__name__ :
205
+ coro_name = coro .__name__
206
+ else :
207
+ # Stop masking Cython bugs, expose them in a friendly way.
208
+ coro_name = f'<{ type (coro ).__name__ } without __name__>'
209
+ return f'{ coro_name } ()'
200
210
201
- running = False
211
+ def is_running ( coro ):
202
212
try :
203
- running = coro .cr_running
213
+ return coro .cr_running
204
214
except AttributeError :
205
215
try :
206
- running = coro .gi_running
216
+ return coro .gi_running
207
217
except AttributeError :
208
- pass
218
+ return False
209
219
210
- if running :
220
+ coro_code = None
221
+ if hasattr (coro , 'cr_code' ) and coro .cr_code :
222
+ coro_code = coro .cr_code
223
+ elif hasattr (coro , 'gi_code' ) and coro .gi_code :
224
+ coro_code = coro .gi_code
225
+
226
+ coro_name = get_name (coro )
227
+
228
+ if not coro_code :
229
+ # Built-in types might not have __qualname__ or __name__.
230
+ if is_running (coro ):
211
231
return f'{ coro_name } running'
212
232
else :
213
233
return coro_name
214
234
215
- coro_name = None
216
- if isinstance (coro , CoroWrapper ):
217
- func = coro .func
218
- coro_name = coro .__qualname__
219
- if coro_name is not None :
220
- coro_name = f'{ coro_name } ()'
221
- else :
222
- func = coro
223
-
224
- if coro_name is None :
225
- coro_name = format_helpers ._format_callback (func , (), {})
226
-
227
- try :
228
- coro_code = coro .gi_code
229
- except AttributeError :
230
- coro_code = coro .cr_code
231
-
232
- try :
235
+ coro_frame = None
236
+ if hasattr (coro , 'gi_frame' ) and coro .gi_frame :
233
237
coro_frame = coro .gi_frame
234
- except AttributeError :
238
+ elif hasattr ( coro , 'cr_frame' ) and coro . cr_frame :
235
239
coro_frame = coro .cr_frame
236
240
237
- filename = coro_code .co_filename
241
+ # If Cython's coroutine has a fake code object without proper
242
+ # co_filename -- expose that.
243
+ filename = coro_code .co_filename or '<empty co_filename>'
244
+
238
245
lineno = 0
239
- if (isinstance ( coro , CoroWrapper ) and
240
- not inspect . isgeneratorfunction ( coro .func ) and
241
- coro .func is not None ):
246
+ if (is_corowrapper and
247
+ coro .func is not None and
248
+ not inspect . isgeneratorfunction ( coro .func ) ):
242
249
source = format_helpers ._get_function_source (coro .func )
243
250
if source is not None :
244
251
filename , lineno = source
245
252
if coro_frame is None :
246
253
coro_repr = f'{ coro_name } done, defined at { filename } :{ lineno } '
247
254
else :
248
255
coro_repr = f'{ coro_name } running, defined at { filename } :{ lineno } '
256
+
249
257
elif coro_frame is not None :
250
258
lineno = coro_frame .f_lineno
251
259
coro_repr = f'{ coro_name } running at { filename } :{ lineno } '
260
+
252
261
else :
253
262
lineno = coro_code .co_firstlineno
254
263
coro_repr = f'{ coro_name } done, defined at { filename } :{ lineno } '
0 commit comments