Async failure when returning a coroutine from a decorator with asyncio #1573

Open
scopatz opened this Issue Jan 3, 2017 · 1 comment

Projects

None yet

1 participant

@scopatz
scopatz commented Jan 3, 2017

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:

def dec(f):
    async def bound(*args, **kwargs):
        print("from cython coro qualname", bound.__qualname__)
    return bound

@dec
async def foo():
    print("in foo")

loop = asyncio.get_event_loop()
loop.run_until_complete(foo())

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__')
    else:
        func_repr = repr(func)

    if args is not None:
        func_repr += _format_args(args)
    if suffix:
        func_repr += suffix
    return func_rep

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.

@scopatz scopatz referenced this issue in cyclus/cyclus Jan 4, 2017
Merged

Cyclus Server #1337

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment