list/dict/set comprehensions#
В list/dict/set comprehensions можно использовать await и, при переборе
асинхронного итератора - async for.
Пример использования list comprehensions в сопрограмме:
from pprint import pprint
import asyncio
import yaml
from scrapli import AsyncScrapli
from scrapli.exceptions import ScrapliException
async def send_show(device, command):
print(f">>> connect to {device['host']}")
try:
async with AsyncScrapli(**device) as conn:
result = await conn.send_command(command)
return result.result
except ScrapliException as error:
print(error, device["host"])
async def send_command_to_devices(devices, commands):
tasks = [asyncio.create_task(send_show(device, commands)) for device in devices]
result = [await task for task in tasks]
return result
if __name__ == "__main__":
with open("devices_async.yaml") as f:
devices = yaml.safe_load(f)
result = asyncio.run(send_command_to_devices(devices, "sh clock"))
pprint(result, width=120)
Тут с помощью обычного list comprehensions (без async/await) создается список задач:
tasks = [asyncio.create_task(send_show(device, commands)) for device in devices]
А в этом используется await чтобы получить результаты каждой задачи:
result = [await task for task in tasks]
Также в list comprehensions может использоваться async for, при переборе
асинхронного итератора.
import asyncio from pprint import pprint
from datetime import datetime
from scrapli import AsyncScrapli
from scrapli.exceptions import ScrapliException
import yaml
class CheckConnection:
def __init__(self, device_list):
self.device_list = device_list
self._current_device = 0
async def _scan_device(self, device):
ip = device["host"]
try:
async with AsyncScrapli(**device) as conn:
prompt = await conn.get_prompt()
return True, prompt
except (ScrapliException, asyncio.exceptions.TimeoutError) as error:
return False, f"{error} {ip}"
async def __anext__(self):
if self._current_device >= len(self.device_list):
raise StopAsyncIteration
device_params = self.device_list[self._current_device]
scan_results = await self._scan_device(device_params)
self._current_device += 1
return scan_results
def __aiter__(self):
return self
async def ssh_scan(devices):
check = CheckConnection(devices)
results = [out async for out in check]
return results
if __name__ == "__main__":
with open("devices_asyncssh.yaml") as f:
devices = yaml.safe_load(f)
result = asyncio.run(ssh_scan(devices))
pprint(result)
for status, msg in result:
if status:
print(f"{datetime.now()} SSH. Подключение успешно: {msg}")
else:
print(f"{datetime.now()} SSH. Не удалось подключиться: {msg}")
В примере выше в list comp используется именно async for потому что выполняется
перебор асинхронного итератора:
results = [out async for out in check]