当 pysftp 连接失败时,“'Connection' 对象没有属性 '_sftp_live'”
"'Connection' object has no attribute '_sftp_live'" when pysftp connection fails
我想在 “找不到主机 *** 的主机密钥” 时很好地捕获错误,并向最终用户提供适当的消息。我试过这个:
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'
如何使用 try: except:
?
很好地避免这些最后几行/这个“被忽略的异常”
我认为这是 pysftp 中的错误。当 pysftp.Connection
在 No hostkey for XXX found
异常上失败时,你将始终有这种行为,因为失败的 Connection
对象(它失败所以你无法访问它,但它存在于 Python 解释器)被 GC 清除,GC 将其删除,正如您所见 here,它首先尝试关闭连接。
我们看到 close()
checks whether the connection is live by checking self._sftp_live
. However, the Exception was thrown in the constructor of Connection
before that attribute is defined (the exception happens line 132, while _sftp_live
is defined line 134),因此失败的 Connection
对象处于不一致状态,因此您会看到未捕获的异常。
除了为 pysftp 项目引入一个很好的错误修复之外,我没有想到简单的解决方案 ;)
@reverse_engineer的分析是正确的。然而:
- 似乎附加属性
self._transport
也定义得太晚了。
- 问题 可以 暂时更正,直到永久修复通过 class 对
pysftp.Connection
class 进行如下修改:
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
的源代码,它使用 self._cnopts = cnopts or CnOpts()
初始化其 _cnopts
属性,其中 cnopts
是 pysftp.Connection
构造函数的关键字参数如果没有找到主机密钥导致 _cnopts
属性未设置,CnOpts
构造函数可能会抛出 HostKeysException
异常。
试试下面的更新代码,如果有效请告诉我:
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)
我遇到了同样的问题。我通过禁用 cnops 中的主机密钥解决了这个问题:
import pysftp as sftp
FTP_HOST = "sftp.abcd.com"
FTP_USER = "root"
FTP_PASS = ""
cnopts = sftp.CnOpts()
cnopts.hostkeys = None
with sftp.Connection(host=FTP_HOST, username=FTP_USER, password=FTP_PASS, cnopts=cnopts) as sftp:
print("Connection succesfully stablished ... ")
sftp.cwd('/folder/') # Switch to a remote directory
directory_structure = sftp.listdir_attr() # Obtain structure of the remote directory
for attr in directory_structure:
print(attr.filename, attr)
我想在 “找不到主机 *** 的主机密钥” 时很好地捕获错误,并向最终用户提供适当的消息。我试过这个:
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'
如何使用 try: except:
?
我认为这是 pysftp 中的错误。当 pysftp.Connection
在 No hostkey for XXX found
异常上失败时,你将始终有这种行为,因为失败的 Connection
对象(它失败所以你无法访问它,但它存在于 Python 解释器)被 GC 清除,GC 将其删除,正如您所见 here,它首先尝试关闭连接。
我们看到 close()
checks whether the connection is live by checking self._sftp_live
. However, the Exception was thrown in the constructor of Connection
before that attribute is defined (the exception happens line 132, while _sftp_live
is defined line 134),因此失败的 Connection
对象处于不一致状态,因此您会看到未捕获的异常。
除了为 pysftp 项目引入一个很好的错误修复之外,我没有想到简单的解决方案 ;)
@reverse_engineer的分析是正确的。然而:
- 似乎附加属性
self._transport
也定义得太晚了。 - 问题 可以 暂时更正,直到永久修复通过 class 对
pysftp.Connection
class 进行如下修改:
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
的源代码,它使用 self._cnopts = cnopts or CnOpts()
初始化其 _cnopts
属性,其中 cnopts
是 pysftp.Connection
构造函数的关键字参数如果没有找到主机密钥导致 _cnopts
属性未设置,CnOpts
构造函数可能会抛出 HostKeysException
异常。
试试下面的更新代码,如果有效请告诉我:
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)
我遇到了同样的问题。我通过禁用 cnops 中的主机密钥解决了这个问题:
import pysftp as sftp
FTP_HOST = "sftp.abcd.com"
FTP_USER = "root"
FTP_PASS = ""
cnopts = sftp.CnOpts()
cnopts.hostkeys = None
with sftp.Connection(host=FTP_HOST, username=FTP_USER, password=FTP_PASS, cnopts=cnopts) as sftp:
print("Connection succesfully stablished ... ")
sftp.cwd('/folder/') # Switch to a remote directory
directory_structure = sftp.listdir_attr() # Obtain structure of the remote directory
for attr in directory_structure:
print(attr.filename, attr)