Как указал JimB , это проблема импорта , когда python пытается неявно импортировать декодер str.decode('utf-8')
при первом использовании во время попытки соединения ssh. Подробности см. В разделе Анализ .
В общем, нельзя не подчеркнуть, что вам следует избегать автоматического создания новых потоков при импорте. Если вы можете, старайтесь избегать магического кода модуля в целом, так как он почти всегда приводит к нежелательным побочным эффектам.
Простое и разумное решение вашей проблемы, как уже упоминалось, состоит в том, чтобы поместить ваш код в тело if __name__ == '__main__':
, которое будет выполняться только в том случае, если вы выполняете этот конкретный модуль и не будет выполняться при использовании этого модуля импортируется другими модулями.
(не рекомендуется) Еще одно исправление - просто ввести в коде фиктивный код str. ('utf-8') перед вызовом SSHClient.connect()
- см. Анализ ниже.
Так в чем же причина этой проблемы?
Анализ (простой пароль аутентификации)
Подсказка: если вы хотите отладить многопоточность в импорте Python, установите threading._VERBOSE = True
paramiko.SSHClient().connect(.., look_for_keys=False, ..)
неявно порождает новый поток для вашего соединения. Вы также можете увидеть это, если включите отладочный вывод для paramiko.transport
.
[Thread-5 ] [paramiko.transport ] DEBUG : starting thread (client mode): 0x317f1d0L
это в основном делается как часть SSHClient.connect()
. Когда вызывается client.py:324::start_client()
, создается блокировка transport.py:399::event=threading.Event()
и запускается поток transport.py:400::self.start()
. Обратите внимание, что метод start()
затем выполнит метод класса transport.py:1565::run()
.
transport.py:1580::self._log(..)
печатает наше лог-сообщение «Начальная нить» и затем переходит к transport.py:1584::self._check_banner()
.
check_banner
делает одну вещь. Он получает баннер ssh (первый ответ от сервера) transport.py:1707::self.packetizer.readline(timeout)
(обратите внимание, что тайм-аут - это просто тайм-аут чтения сокета), в конце проверяет перевод строки.
и в противном случае время ожидания.
В случае, если баннер сервера был получен, он пытается utf-8 декодировать строку ответа packet.py:287::return u(buf)
, и именно там происходит тупик. u(s, encoding='utf-8')
выполняет код str. ('utf-i') и неявно импортирует encodings.utf8
в encodings:99
через encodings.search_function
, в результате чего блокируется импорт.
Так что грязным решением было бы просто импортировать декодер utf-8 один раз, чтобы не блокировать этот специфический импорт из-за побочных эффектов импорта модуля. (''.decode('utf-8')
)
Fix
грязное исправление - не рекомендуется
import paramiko
hostname,username,password='fill','these','in'
''.decode('utf-8') # dirty fix
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(hostname=hostname, username=username, password=password)
i,o,e = c.exec_command('ls /')
print(o.read())
c.close()
исправление
import paramiko
if __name__ == '__main__':
hostname,username,password='fill','these','in'
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(hostname=hostname, username=username, password=password)
i,o,e = c.exec_command('ls /')
print(o.read())
c.close()
ref средство отслеживания проблем paramiko: выпуск 104