Асинхронный менеджер контекста#

В целом, смысл работы асинхронного менеджера контекста остается таким же, как и в синхронном. Только так как методы для подключения к устройству являются сопрограммами, их надо правильно ожидать (await) и соответственно специальные методы для создания асинхронного менеджера контекста, тоже должны быть сопрограммами. Поэтому для асинхронного менеджера контекста созданы отдельные специальные методы __aenter__ и __aexit__ и соответственно чтобы они вызывались, надо использовать асинхронный менеджер контекста async with, а не обычный with.

Примечание

async with можно использовать только внутри сопрограммы.

Пример класса с поддержкой протокола асинхронного менеджера контекста:

from pprint import pprint
import asyncio
import asyncssh


class ConnectAsyncSSH:
    def __init__(self, host, username, password, enable_password, connection_timeout=5):
        self.host = host
        self.username = username
        self.password = password
        self.enable_password = enable_password
        self.connection_timeout = connection_timeout

    async def connect(self):
        self._ssh = await asyncio.wait_for(
            asyncssh.connect(
                host=self.host,
                username=self.username,
                password=self.password,
                encryption_algs="+aes128-cbc,aes256-cbc",
            ),
            timeout=self.connection_timeout,
        )
        self.writer, self.reader, _ = await self._ssh.open_session(
            term_type="Dumb", term_size=(200, 24)
        )
        await self.reader.readuntil(">")
        self.writer.write("enable\n")
        await self.reader.readuntil("Password")
        self.writer.write(f"{self.enable_password}\n")
        await self.reader.readuntil("#")
        self.writer.write("terminal length 0\n")
        await self.reader.readuntil("#")

    async def get_prompt(self):
        self.writer.write("\n")
        output = await self.reader.readuntil("#")
        return output

    def close(self):
        self._ssh.close()

    async def __aenter__(self):
        await self.connect()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        self.close()

Пример использования:

async def main():
    r1 = {
        "host": "192.168.100.1",
        "username": "cisco",
        "password": "cisco",
        "enable_password": "cisco",
    }
    async with ConnectAsyncSSH(**r1) as ssh:
        print(await ssh.get_prompt())


if __name__ == "__main__":
    asyncio.run(main())