Suppose you have a decorator for async functions that returns an async function. When used with the asyncio module from the standard library, a decorator written in Cython will fail and can take the event loop / kernel with it. A full, minimal example is given in this notebook, https://gist.github.com/scopatz/78d1750517af479d0b42997873ff9c4a The basic idea though is that the following does not work in Cython but does in Python:
async def bound(*args, **kwargs):
print("from cython coro qualname", bound.__qualname__)
async def foo():
loop = asyncio.get_event_loop()
Some code I was writing in for a library leads me to believe that this error is because the bound() coroutine object (not the coroutine function) has a __qualname__ attribute that exists and is set to None, rather than a string.
This is problematic because of the way asyncio is written. In the asyncio/events.py on line 65 (of Python 3.5.2), there is a function called _format_callback(). This is below:
def _format_callback(func, args, suffix=''):
if isinstance(func, functools.partial):
if args is not None:
suffix = _format_args(args) + suffix
return _format_callback(func.func, func.args, suffix)
if hasattr(func, '__qualname__'):
func_repr = getattr(func, '__qualname__')
elif hasattr(func, '__name__'):
func_repr = getattr(func, '__name__')
func_repr = repr(func)
if args is not None:
func_repr += _format_args(args)
func_repr += suffix
This searches for qualname on the callback (which is there), and the does a +=, and this leads to a TypeError. This function gets called a lot for logging and error reporting.
What is more is that assigning a str qualname to bound() inside of the decorator didn't seem to have any affect. I think the fix is to either make sure that qualname is a string or that it doesn't exist.
I hope this helps and please let me know if you need anymore information.
This line seems like it could be the problem: https://github.com/cython/cython/blob/176ed5e41e30520dbad4a5c3b9d4cc34cb84a359/Cython/Utility/Coroutine.c#L986