@@ -189,66 +189,75 @@ def iscoroutine(obj):
189189def _format_coroutine (coro ):
190190 assert iscoroutine (coro )
191191
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 } ()'
200210
201- running = False
211+ def is_running ( coro ):
202212 try :
203- running = coro .cr_running
213+ return coro .cr_running
204214 except AttributeError :
205215 try :
206- running = coro .gi_running
216+ return coro .gi_running
207217 except AttributeError :
208- pass
218+ return False
209219
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 ):
211231 return f'{ coro_name } running'
212232 else :
213233 return coro_name
214234
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 :
233237 coro_frame = coro .gi_frame
234- except AttributeError :
238+ elif hasattr ( coro , 'cr_frame' ) and coro . cr_frame :
235239 coro_frame = coro .cr_frame
236240
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+
238245 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 ) ):
242249 source = format_helpers ._get_function_source (coro .func )
243250 if source is not None :
244251 filename , lineno = source
245252 if coro_frame is None :
246253 coro_repr = f'{ coro_name } done, defined at { filename } :{ lineno } '
247254 else :
248255 coro_repr = f'{ coro_name } running, defined at { filename } :{ lineno } '
256+
249257 elif coro_frame is not None :
250258 lineno = coro_frame .f_lineno
251259 coro_repr = f'{ coro_name } running at { filename } :{ lineno } '
260+
252261 else :
253262 lineno = coro_code .co_firstlineno
254263 coro_repr = f'{ coro_name } done, defined at { filename } :{ lineno } '
0 commit comments