I'm using Python 3.7.4 and this block of code (MWE):
import asyncio
async def foo(x):
    await asyncio.sleep(1)
    return [i for i in range(10)]
async def big_foo():
    dict_of_lists = {'A': [i for i in range(10)], 'B': [i for i in range(10)]}
    return {
        key: [
            item
            for list_item in dict_of_lists[key]
            for item in await foo(list_item)
        ]
        for key in ['A', 'B']
    }
Throws the error:
File "filename.py", line 13
    item
    ^
SyntaxError: asynchronous comprehension outside of an asynchronous function
The error message doesn't help a lot because it is indeed inside an asynchronous function.
I solved the issue by defining explicit for loops instead of a comprehension, like this:
async def big_foo():
    dict_of_lists = {'A': [i for i in range(10)], 'B': [i for i in range(10)]}
    var = {}
    for key in ['A', 'B']:
        var[key] = []
        for list_item in dict_of_lists[key]:
            for item in await foo(list_item):
                var[key].append(item)
    return var
It bugs me that removing the dictionary outer loop also removes the error.
This works (it doesn't accomplish what I need obviously):
async def other_foo():
    dict_of_lists = {'A': [i for i in range(10)]}
    return [
        item
        for list_item in dict_of_lists['A']
        for item in await foo(list_item)
    ]
I have found the answer. Quoting a co-worker:
The interior comprehension is asynchronous. The exterior one isn't. The function is asynchronous. The error is triggered because you are defining as an asynchronous comprehension inside of a non-asynchronous context - the error message is indeed wrong and it's a know bug.
https://bugs.python.org/issue33346
I fixed it by setting an
async forin the exterior comprehension. Like this:
async def big_foo():
    dict_of_lists = {'A': [i for i in range(10)], 'B': [i for i in range(10)]}
    return {
        key: [
            item
            for list_item in dict_of_lists[key]
            for item in await foo(list_item)
        ]
        async for key in ['A', 'B']
    }
While this removes the mentioned SyntaxError it introduces a TypeError: 'async for' requires an object with __aiter__ method, got tuple. So the solution would be to define a wraper for it, but it looks more like a hack than a proper solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With