Why does this fail with "'async for' requires an object with __aiter__ method, got coroutine"
Asked Answered
D

2

8

I am attempting to call an external API (one that is provided by Google) using an async client library (the library is also provided by Google).

The async method that I am attempting to call is async list_featurestores() (documentation). It provides the following sample code:

from google.cloud import aiplatform_v1

async def sample_list_featurestores():
    # Create a client
    client = aiplatform_v1.FeaturestoreServiceAsyncClient()

    # Initialize request argument(s)
    request = aiplatform_v1.ListFeaturestoresRequest(
        parent="parent_value",
    )

    # Make the request
    page_result = client.list_featurestores(request=request)

    # Handle the response
    async for response in page_result:
        print(response)

(I've literally copy/pasted that code from the above linked page).

In order to run that code I've slightly adapted it to:

import asyncio
from google.cloud import aiplatform_v1

async def sample_list_featurestores():
    client = aiplatform_v1.FeaturestoreServiceAsyncClient()
    request = aiplatform_v1.ListFeaturestoresRequest(parent="projects/MY_GCP_PROJECT/locations/europe-west2",)
    page_result  = client.list_featurestores(request=request)
    async for response in page_result:
        print(response)


if __name__ == "__main__":
    asyncio.run(sample_list_featurestores())

When I run it it fails on this line: async for response in page_result: with error:

'async for' requires an object with aiter method, got coroutine

This is my first foray into async python development and, given I (think I) have followed the supplied code to the letter I don't know why I'm getting this error.

Am I missing something obvious here? Can someone explain how to get past this error?

Diplegia answered 20/7, 2022 at 16:25 Comment(8)
Hitting the same error with documentai service - these list_xxx methods do not seem to return true async generators. Did you find a workaround ?Psychological
As list is usually small, I used the blocking sync client to call the list method. These correctly return generators.Psychological
Why did you revert your post to a version with a broken link?Shelah
Which link is broken? I only see one link in this post (googleapis.dev/python/aiplatform/latest/aiplatform_v1/…) and it is not broken. It does lead somewhere, even if it uses a redirect. I reverted your edit because it hyperlinked the word "here" which I dislike (this explains why: heyoka.medium.com/dont-use-click-here-f32f445d1021).Diplegia
Okay, display the URL if you prefer, but keep the nice link to the specific section... Also if you want a descriptive link and a less cluttered post, why not something like "([documentation] here)"? The article you linked to specifically recommends against using URLS themselves as links.Humerus
(Or just make the method itself a link, that is what you're linking to after all.)Humerus
Looks weird, their example seems broken. Maybe a package version problem?Chiasma
I cant understand why the function is awaited. And if the page_result is already there, which is a dict, the need to async loop.Lowery
A
1

Try using "await":

# Make the request
page_result = await client.list_featurestores(request=request)
Anile answered 8/6, 2023 at 23:44 Comment(0)
L
0

If anybody is looking for properly looping through and getting response from an async function. We can use ensure_future and gather from asyncio

async def some_async_task(client, d):
    # Await and do something with client
    return

from asyncio import run, ensure_future, gather
data = ['a', 'b', 'c']

def main():
    async with AnAsyncClient() as client:
        tasks = [
                    ensure_future(
                        some_async_task(client, d)
                    ) for d in data
                ]
        all_data = await gather(* tasks)
        print(all_data)

run(main())
Lowery answered 25/5, 2024 at 15:57 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.