提问者:小点点

pysftp连接失败时,“'Connection'对象没有属性'\u sftp\u live'”


我想很好地捕捉“找不到主机***的主机密钥”时的错误,并向最终用户提供适当的消息。我试过这个:

import pysftp, paramiko
try: 
    with pysftp.Connection('1.2.3.4', username='root', password='') as sftp:
        sftp.listdir()
except paramiko.ssh_exception.SSHException as e:
    print('SSH error, you need to add the public key of your remote in your local known_hosts file first.', e)

但不幸的是,输出不是很好:

SSH error, you need to add the public key of your remote in your local known_hosts file first. No hostkey for host 1.2.3.4 found.
Exception ignored in: <function Connection.__del__ at 0x00000000036B6D38>
Traceback (most recent call last):
  File "C:\Python37\lib\site-packages\pysftp\__init__.py", line 1013, in __del__
    self.close()
  File "C:\Python37\lib\site-packages\pysftp\__init__.py", line 784, in close
    if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'

如何通过尝试:except:很好地避免最后几行/这个“异常被忽略”?


共2个答案

匿名用户

@reverse_engineer的分析是正确的。然而:

  1. 似乎还有一个附加属性,self_传输,也定义得太晚
  2. 该问题可以通过子类化pysftp暂时解决,直到永久性修复。连接分类如下:
import pysftp
import paramiko


class My_Connection(pysftp.Connection):
    def __init__(self, *args, **kwargs):
        self._sftp_live = False
        self._transport = None
        super().__init__(*args, **kwargs)

try: 
    with My_Connection('1.2.3.4', username='root', password='') as sftp:
        l = sftp.listdir()
        print(l)
except paramiko.ssh_exception.SSHException as e:
    print('SSH error, you need to add the public key of your remote in your local known_hosts file first.', e)

最新消息

我无法在桌面上复制此错误。但是,我在代码中的pysftp源代码中看到它用自身初始化其_cnopts属性。_cnopts=cnopt或CnOpts()其中cnopt是pysftp的关键字参数。连接构造函数,并且如果没有找到导致_cnopts属性未被设置的主机密钥,则有可能由CnOpts构造函数抛出HostKeysExc0019异常。

请尝试以下更新的代码,并告知其是否有效:

import pysftp
import paramiko

class My_Connection(pysftp.Connection):
    def __init__(self, *args, **kwargs):
        try:
            if kwargs.get('cnopts') is None:
                kwargs['cnopts'] = pysftp.CnOpts()
        except pysftp.HostKeysException as e:
            self._init_error = True
            raise paramiko.ssh_exception.SSHException(str(e))
        else:
            self._init_error = False

        self._sftp_live = False
        self._transport = None
        super().__init__(*args, **kwargs)

    def __del__(self):
        if not self._init_error:
            self.close()

try:
    with My_Connection('1.2.3.4', username='root', password='') as sftp:
        l = sftp.listdir()
        print(l)
except paramiko.ssh_exception.SSHException as e:
    print('SSH error, you need to add the public key of your remote in your local known_hosts file first.', e)

匿名用户

我认为这是PySTFP中的一个bug。当pysftp时,您将始终具有这种行为。连接失败,因为失败的连接对象(它失败了,所以您无法访问它,但它存在于Python解释器中)被GC清除,GC将删除它,正如您在这里看到的,它首先尝试关闭连接。

我们看到close()通过检查self来检查连接是否处于活动状态_sftp_现场直播。但是,在定义该属性之前,连接的构造函数中抛出了异常(异常发生在第132行,而\u sftp\u live定义在第134行),这样会使失败的连接对象处于不一致的状态,因此会出现未捕获的异常。

除了为PySTFP项目引入一个很好的bug修复之外,我想不出什么简单的解决方案;)