Pergunta

Coloque o seguinte em um arquivo hello.py (e easy_install paramiko se você não tem isso):

hostname,username,password='fill','these','in'
import paramiko
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()

Preencha a primeira linha de forma adequada.

Agora digite

python hello.py

e você verá alguma saída ls.

Agora, em vez digite

python

e, em seguida, a partir do tipo de interpretador

import hello

e voila! Ele trava! Ele vai despendurar se você coloque o código em um foo função e fazer import hello; hello.foo() vez.

Por que paramiko jeito quando utilizados dentro de inicialização do módulo? Como é paramiko mesmo ciente de que ele está sendo usado durante a inicialização do módulo em primeiro lugar?

Foi útil?

Solução

paramiko usa segmentos separados para o transporte subjacente. Você deve não tem um módulo que gera um thread como um efeito colateral de importação. Pelo que entendi, não há um único bloqueio de importação disponível, por isso, quando um segmento de criança do seu módulo tenta outra importação, ele pode bloquear indefinidamente, porque o seu segmento principal ainda mantém o bloqueio. (Há provavelmente outras armadilhas que eu não estou ciente de também)

Em geral, os módulos não deve ter efeitos colaterais de qualquer tipo ao importar, ou você está indo para obter resultados imprevisíveis. Apenas adiar a execução com o truque __name__ == '__main__', e você vai ficar bem.

[EDIT] Eu não consigo criar um caso de teste simples que reproduz esse impasse. Eu ainda assumir que é um problema de segmentação com importação, porque o código de autenticação está à espera de um evento que nunca incêndios. Este pode ser um bug no paramiko, ou Python, mas a boa notícia é que você não deve nunca vê-lo se você fizer as coisas corretamente;)

Este é um exemplo bom porque você sempre quer minimizar os efeitos colaterais, e por técnicas de programação funcionais estão se tornando mais prevalente.

Outras dicas

Como JimB apontou que é um edição import quando tenta python importar implicitamente a descodificador str.decode('utf-8') na primeira utilização durante uma tentativa de conexão SSH. Veja Análise para obter detalhes.

Em geral, não se pode forçar bastante que você deve evitar ter um módulo automaticamente gerando novos tópicos na importação. Se você puder, para tentar evitar o código do módulo magia em geral, uma vez que quase sempre leva a efeitos colaterais indesejados.

  1. O fácil - e sã - correção para o problema - como já mencionado - é colocar seu código em um corpo if __name__ == '__main__': que só será executado se você executar este módulo específico e não vai ser executado quando este mmodule é importado por outros módulos.

  2. (não recomendado) Outra correção é apenas fazer uma str.decode manequim ( 'utf-8') em seu código antes de chamar SSHClient.connect() -. Veja análise abaixo

Assim que é a causa raiz do problema?

Análise (auth senha simples)

Dica: Se você quiser enfiar depuração na importação python e conjunto threading._VERBOSE = True

  1. paramiko.SSHClient().connect(.., look_for_keys=False, ..) gera implicitamente um novo segmento para a sua conexão. Você também pode ver isso se você ativar a saída de depuração para paramiko.transport.

[Thread-5 ] [paramiko.transport ] DEBUG : starting thread (client mode): 0x317f1d0L

  1. Este é basicamente feito como parte de SSHClient.connect(). Quando client.py:324::start_client() é chamado, um bloqueio é criado transport.py:399::event=threading.Event() eo segmento é iniciado transport.py:400::self.start(). Note que o método start() irá então executar método transport.py:1565::run() da classe.

  2. transport.py:1580::self._log(..) imprime a nossa mensagem de log "a partir thread" e então começa a transport.py:1584::self._check_banner().

  3. check_banner faz uma coisa. Ele recupera a bandeira ssh (primeira resposta do servidor) transport.py:1707::self.packetizer.readline(timeout) (note que o tempo limite é apenas um limite do soquete ler), cheques para um avanço de linha no final e de outra forma expira.

  4. No caso de um banner servidor foi recebido, ele tenta utf-8 decodificar o packet.py:287::return u(buf) cadeia de resposta e é onde o impasse acontece. O u(s, encoding='utf-8') faz um str.decode ( 'utf-i') e implicitamente importações encodings.utf8 em encodings:99 via encodings.search_function acabar em um impasse de importação.

Assim, uma correção sujo seria apenas para importar o decodificador utf-8 uma vez, a fim de não bloquear em que a importação specifiy devido a efeitos colaterais de importação do módulo. (''.decode('utf-8'))

Fix

correção sujo - não é recomendado

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()

boa correção

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()

paramiko issue tracker: emissão 104

"". Decodificação ( "utf-8") não funcionou para mim, eu acabei fazendo isso.

from paramiko import py3compat
# dirty hack to fix threading import lock (issue 104) by preloading module
py3compat.u("dirty hack")

Eu tenho um wrapper para paramiko com que implementou. https://github.com/bucknerns/sshaolin

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top