J'ai un API asynchrone que j'utilise pour me connecter et envoyer du courrier à un serveur SMTP qui a une configuration et un démontage. Il s'intègre donc parfaitement dans l'utilisation d'un contextmanager
de Python 3's contextlib
.
Cependant, je ne sais pas si c'est possible d'écrire car ils utilisent tous les deux la syntaxe du générateur pour écrire.
Cela pourrait démontrer le problème (contient un mélange de syntaxe de base de rendement et d'attente asynchrone pour démontrer la différence entre les appels asynchrones et les rendements au gestionnaire de contexte).
@contextmanager
async 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()
Est-ce que ce genre de chose est possible dans python actuellement? Et comment pourrais-je utiliser une instruction with
as
si elle l'est? Sinon, existe-t-il une autre façon pourrait y parvenir - peut-être en utilisant l'ancien gestionnaire de contexte de style?
Merci à @jonrsharpe a pu créer un gestionnaire de contexte asynchrone.
Voici à quoi ressemblait le mien pour tous ceux qui veulent un exemple de 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(...)
N'hésitez pas à signaler si j'ai fait quelque chose de stupide.
Dans Python 3.7, vous pourrez écrire:
from contextlib import asynccontextmanager
@asynccontextmanager
async 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()
Jusqu'à la sortie de la version 3.7, vous pouvez utiliser le async_generator
package pour cela. Sur 3.6, vous pouvez écrire:
# This import changed, everything else is the same
from async_generator import asynccontextmanager
@asynccontextmanager
async 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()
Et si vous souhaitez revenir à la version 3.5, vous pouvez écrire:
# This import changed again:
from async_generator import asynccontextmanager, async_generator, yield_
@asynccontextmanager
@async_generator # <-- added this
async 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()
Le paquet asyncio_extras a une belle solution pour cela:
import asyncio_extras
@asyncio_extras.async_contextmanager
async def smtp_connection():
client = SMTPAsync()
...
Pour Python <3.6, vous auriez également besoin du paquet async_generator et remplacer yield client
Par await yield_(client)
.