"async With" In Python 3.4
Solution 1:
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 you could ignore that here:
@asyncio.coroutinedeffetch(session, url):
with aiohttp.Timeout(10):
response = yieldfrom session.get(url)
return (yieldfrom 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).
If you have more statements between the session.get()
call and accessing the response.text()
awaitable, you probably want to use a try:..finally:
anyway to release the connection; the Python 3.5 release context manager also closes the response if an exception occurred. Because a yield from response.release()
is needed here, this can't be encapsulated in a context manager before Python 3.4:
import sys
@asyncio.coroutinedeffetch(session, url):
with aiohttp.Timeout(10):
response = yieldfrom session.get(url)
try:
# other statementsreturn (yieldfrom response.text())
finally:
if sys.exc_info()[0] isnotNone:
# on exceptions, close the connection altogether
response.close()
else:
yieldfrom response.release()
Solution 2:
aiohttp
's examples implemented using 3.4 syntax. Based on json client example your function would be:
@asyncio.coroutinedeffetch(session, url):
with aiohttp.Timeout(10):
resp = yieldfrom session.get(url)
try:
return (yieldfrom resp.text())
finally:
yieldfrom resp.release()
Upd:
Note that Martijn's solution would work for simple cases, but may lead to unwanted behavior in specific cases:
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(5):
response = yieldfrom session.get(url)
# Any actions that may lead to error:1/0return (yieldfrom response.text())
# exception + warning "Unclosed response"
Besides exception you'll get also warning "Unclosed response". This may lead to connections leak in complex app. You will avoid this problem if you'll manually call resp.release()
/resp.close()
:
@asyncio.coroutinedeffetch(session, url):
with aiohttp.Timeout(5):
resp = yieldfrom session.get(url)
try:
# Any actions that may lead to error:1/0return (yieldfrom resp.text())
except Exception as e:
# .close() on exception.
resp.close()
raise e
finally:
# .release() otherwise to return connection into free connection pool.# It's ok to release closed response:# https://github.com/KeepSafe/aiohttp/blob/master/aiohttp/client_reqrep.py#L664yieldfrom resp.release()
# exception only
I think it's better to follow official examples (and __aexit__
implementation) and call resp.release()
/resp.close()
explicitly.
Post a Comment for ""async With" In Python 3.4"