Asynchronous context manager Asynchronous context manager python python

Asynchronous context manager


Since Python 3.7, you can write:

from contextlib import asynccontextmanager@asynccontextmanagerasync def smtp_connection():    client = SMTPAsync()    ...    try:        await client.connect(smtp_url, smtp_port)        await client.starttls()        await client.login(smtp_username, smtp_password)        yield client    finally:        await client.quit()

Before 3.7, you can use the async_generator package for this. On 3.6, you can write:

# This import changed, everything else is the samefrom async_generator import asynccontextmanager@asynccontextmanagerasync def smtp_connection():    client = SMTPAsync()    ...    try:        await client.connect(smtp_url, smtp_port)        await client.starttls()        await client.login(smtp_username, smtp_password)        yield client    finally:        await client.quit()

And if you want to work all the way back to 3.5, you can write:

# This import changed again:from async_generator import asynccontextmanager, async_generator, yield_@asynccontextmanager@async_generator      # <-- added thisasync def smtp_connection():    client = SMTPAsync()    ...    try:        await client.connect(smtp_url, smtp_port)        await client.starttls()        await client.login(smtp_username, smtp_password)        await yield_(client)    # <-- this line changed    finally:        await client.quit()


Thanks to @jonrsharpe was able to make an async context manager.

Here's what mine ended up looking like for anyone who want's some example code:

class SMTPConnection():    def __init__(self, url, port, username, password):        self.client   = SMTPAsync()        self.url      = url        self.port     = port        self.username = username        self.password = password    async def __aenter__(self):        await self.client.connect(self.url, self.port)        await self.client.starttls()        await self.client.login(self.username, self.password)        return self.client    async def __aexit__(self, exc_type, exc, tb):        await self.client.quit()

usage:

async with SMTPConnection(url, port, username, password) as client:    await client.sendmail(...)

Feel free to point out if I've done anything stupid.


The asyncio_extras package has a nice solution for this:

import asyncio_extras@asyncio_extras.async_contextmanagerasync def smtp_connection():    client = SMTPAsync()    ...

For Python < 3.6, you'd also need the async_generator package and replace yield client with await yield_(client).