Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python async AttributeError aexit

I keep getting error AttributeError: __aexit__ on the code below, but I don't really understand why this happens.

My Python version is: 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)]

import aiohttp
import asyncio
import tqdm


async def fetch_url(session_, url_, timeout_=10):
    with aiohttp.Timeout(timeout_):
        async with session_.get(url_) as response:
            text = await response.text()
            print("URL: {} - TEXT: {}".format(url_, len(text)))
            return text


async def parse_url(session, url, timeout=10):
    # get doc from url
    async with await fetch_url(session, url, timeout) as doc:
        print("DOC: {}".format(doc, len(doc)))
        return doc


async def parse_urls(session, urls, loop):
    tasks = [parse_url(session, url) for url in urls]
    responses = [await f for f in tqdm.tqdm(asyncio.as_completed(tasks), total = len(tasks))]
    return responses


if __name__ == '__main__':

    tickers = ['CTXS', 'MSFT', 'AAPL', 'GPRO', 'G', 'INTC', 'SYNC', 'SYNA']
    urls = ["https://finance.yahoo.com/quote/{}".format(ticker) for ticker in tickers]

    loop = asyncio.get_event_loop()
    with aiohttp.ClientSession(loop=loop) as session:
        parsed_data = loop.run_until_complete(parse_urls(session, urls, loop))
        print(parsed_data)

Error callstack:

C:\Python\Python36\python.exe C:/Users/me/.PyCharmCE2017.3/config/scratches/scratch_4.py
  0%|          | 0/8 [00:00<?, ?it/s]Traceback (most recent call last):
URL: https://finance.yahoo.com/quote/CTXS - TEXT: 462138
  File "C:/Users/me/.PyCharmCE2017.3/config/scratches/scratch_4.py", line 34, in <module>
    parsed_data = loop.run_until_complete(parse_urls(session, urls, loop))
  File "C:\Python\Python36\lib\asyncio\base_events.py", line 467, in run_until_complete
    return future.result()
  File "C:/Users/me/.PyCharmCE2017.3/config/scratches/scratch_4.py", line 23, in parse_urls
    responses = [await f for f in tqdm.tqdm(asyncio.as_completed(tasks), total = len(tasks))]
  File "C:/Users/me/.PyCharmCE2017.3/config/scratches/scratch_4.py", line 23, in <listcomp>
    responses = [await f for f in tqdm.tqdm(asyncio.as_completed(tasks), total = len(tasks))]
  File "C:\Python\Python36\lib\asyncio\tasks.py", line 458, in _wait_for_one
    return f.result()  # May raise f.exception().
  File "C:/Users/me/.PyCharmCE2017.3/config/scratches/scratch_4.py", line 16, in parse_url
    async with await fetch_url(session, url, timeout) as doc:
AttributeError: __aexit__


Process finished with exit code 1
like image 380
Bjorn Mistiaen Avatar asked Feb 05 '18 15:02

Bjorn Mistiaen


People also ask

What is __ Aexit __?

object.__aexit__(self, exc_type, exc_val, exc_tb) Summary: Python's __aexit__() magic method is semantically similar to __exit__() but is used for asynchronous and parallel programming. Python calls the __aexit__() magic method when leaving an async with block whereas the __aenter__() method is called when entering it.

What is Python await?

The keyword await passes function control back to the event loop. (It suspends the execution of the surrounding coroutine.) If Python encounters an await f() expression in the scope of g() , this is how await tells the event loop, “Suspend execution of g() until whatever I'm waiting on—the result of f() —is returned.

What is Asyncio in Python?

asyncio is a library to write concurrent code using the async/await syntax. asyncio is used as a foundation for multiple Python asynchronous frameworks that provide high-performance network and web-servers, database connection libraries, distributed task queues, etc.


1 Answers

You are trying to use fetch_url as a context manager, but it isn't one. You can either make it one

class fetch_url:
    def __init__(self, session, url, timeout=10):
        self.session = session
        self.url = url
        self.timeout = timeout

    async def __aenter__(self):
        with aiohttp.Timeout(self.timeout):
            async with self.session.get(self.url) as response:
                text = await response.text()
                print("URL: {} - TEXT: {}".format(self.url, len(text)))
                return text

    async def __aexit__(self, exc_type, exc, tb):
        # clean up anything you need to clean up

or change your code to

async def parse_url(session, url, timeout=10):
    # get doc from url
    doc = await fetch_url(session, url, timeout)
    print("DOC: {}".format(doc, len(doc)))
    return doc
like image 74
dirn Avatar answered Sep 18 '22 17:09

dirn