Imran Imran - 6 months ago 49
Python Question

"async with" in Python 3.4

The Getting Started docs for aiohttp give the following client example:

import asyncio
import aiohttp

async def fetch_page(session, url):
with aiohttp.Timeout(10):
async with session.get(url) as response:
assert response.status == 200
return await response.read()

loop = asyncio.get_event_loop()
with aiohttp.ClientSession(loop=loop) as session:
content = loop.run_until_complete(
fetch_page(session, 'http://python.org'))
print(content)


And they give the following note for Python 3.4 users:


If you are using Python 3.4, please replace await with yield from and
async def with a @coroutine decorator.


If I follow these instructions I get:

import aiohttp
import asyncio

@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
async with session.get(url) as response:
return (yield from response.text())

if __name__ == '__main__':
loop = asyncio.get_event_loop()
with aiohttp.ClientSession(loop=loop) as session:
html = loop.run_until_complete(
fetch(session, 'http://python.org'))
print(html)


However, this will not run, because
async with
is not supported in Python 3.4:

$ python3 client.py
File "client.py", line 7
async with session.get(url) as response:
^
SyntaxError: invalid syntax


How can I translate the
async with
statement to work with Python 3.4?

Answer

Just don't use the result of session.get() as a context manager; use it as a coroutine directly instead. The request context manager that session.get() produces would normally release the request on exit, but so does using response.text(), so it is safe to ignore that here:

@asyncio.coroutine
def fetch(session, url):) 
    with aiohttp.Timeout(10):
        response = yield from session.get(url)
        return (yield from response.text())

The request wrapper returned here doesn't have the required asynchronous methods (__aenter__ and __aexit__), they omitted entirely when not using Python 3.5 (see the relevant source code).

Comments