2015-05-26 3 views
3

Я пытаюсь сделать автоподключение ssh-клиента на asyncssh. (SshConnectManager должны оставаться в фоновом режиме и сделать SSH сессий, когда нужно)ТипError: Требуется будущее или сопрограмма

class SshConnectManager(object): 
def __init__(self, host, username, password, port=22): 
    self._host = host 
    self._username = username 
    self._password = password 
    self._port = port 

    self.conn = None 
    asyncio.async(self.start_connection) 

@asyncio.coroutine 
def start_connection(self): 
    try: 
     Client = self._create_ssh_client() 
     self.conn, _ = yield from asyncssh.create_connection(Client, 
                 self._host, port=self._port, 
                 username=self._username, 
                 password=self._password) 
    except Exception as e: 
     print("Connection error! {}".format(e)) 
     asyncio.async(self.start_connection()) 

def _create_ssh_client(self): 
    class MySSHClient(asyncssh.SSHClient): 
     parent = self 
     def connection_lost(self, exc): 
      self.parent._handle_connection_lost(exc) 
    return MySSHClient 

def _handle_connection_lost(self, exc): 
    print('Connection lost on {}'.format(self.host)) 
    print(exc) 
    asyncio.async(self.start_connection) 


ssh1 = SshConnectManager(settings.host, settings.username, settings.password, settings.port) 

asyncio.get_event_loop().run_until_complete(...) 

Пожалуйста, не смотрите на _create_ssh_client или других "Haks"

Проблема:

$ python3 main.py 
Traceback (most recent call last): 
    File "main.py", line 75, in <module> 
    ssh1 = SshConnectManager(settings.host, settings.username, settings.password, settings.port) 
    File "main.py", line 22, in __init__ 
    asyncio.async(self.start_connection) 
    File "/usr/lib/python3.4/asyncio/tasks.py", line 565, in async 
    raise TypeError('A Future or coroutine is required') 
TypeError: A Future or coroutine is required 

Но self.start_connection является corutine! Или нет? Или что еще один способ запустить асинхронную задачу из кода синхронизации?

+0

Вы просмотрели _line 565_ из '/ usr/lib/python3.4/asyncio/tasks.py'? – boardrider

+0

Да. Но почему start_connection не является corutine? – kolko

+0

Ох. Нужно позвонить ему, чтобы получить corutine ... – kolko

ответ

1

Спасибо @dano и @boardrider за помощь в комментариях. Ошибка была в том, что @ asyncio.coroutine возвращает функцию, которую нужно вызвать, чтобы получить объект генератора. Я забываю это сделать.

Фиксированная версия:

class SshConnectManager(object): 
def __init__(self, host, username, password, port=22): 
    self._host = host 
    self._username = username 
    self._password = password 
    self._port = port 

    self.conn = None 
    # FIX HERE 
    asyncio.async(self.start_connection()) 

@asyncio.coroutine 
def start_connection(self): 
    try: 
     Client = self._create_ssh_client() 
     self.conn, _ = yield from asyncssh.create_connection(Client, 
                 self._host, port=self._port, 
                 username=self._username, 
                 password=self._password) 
    except Exception as e: 
     print("Connection error! {}".format(e)) 
     asyncio.async(self.start_connection()) 

def _create_ssh_client(self): 
    class MySSHClient(asyncssh.SSHClient): 
     parent = self 
     def connection_lost(self, exc): 
      self.parent._handle_connection_lost(exc) 
    return MySSHClient 

def _handle_connection_lost(self, exc): 
    print('Connection lost on {}'.format(self.host)) 
    print(exc) 
    # AND HERE 
    asyncio.async(self.start_connection()) 


ssh1 = SshConnectManager(settings.host, settings.username, settings.password, settings.port) 

asyncio.get_event_loop().run_until_complete(...) 

P.S. Но я не понимаю, почему декоратор Coroutine не может вернуть призванный декоратор. (Это заставляет меня смущать, я путаю это с искаженными обратными вызовами).

И я нашел, как об этом помнить, имеют простой случай, если start_connection может получить аргументы:

@asyncio.coroutine 
def start_connection(self, some_arg): 
    pass 

так, я могу просто написать:

asyncio.async(self.start_connection(some_val)) 

и не нужно делать дополнительные атрибуты в функции asyncio.async

 Смежные вопросы

  • Нет связанных вопросов^_^