Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"'Connection' object has no attribute '_sftp_live'" when pysftp connection fails

I'd like to catch nicely the error when "No hostkey for host *** is found" and give an appropriate message to the end user. I tried this:

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)

but unfortunately the output is not very nice:

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'

How to nicely avoid these last lines / this "exception ignored" with a try: except:?

like image 281
Basj Avatar asked Dec 13 '22 07:12

Basj


2 Answers

The analysis by @reverse_engineer is correct. However:

  1. It seems that an additional attribute, self._transport, also is defined too late.
  2. The problem can be temporarily corrected until a permanent fix comes by subclassing the pysftp.Connection class as follows:
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)

Update

I could not duplicate this error on my desktop. However, I see in the source for pysftp in the code where it initializes its _cnopts attribute with self._cnopts = cnopts or CnOpts() where cnopts is a keyword parameter to the pysftp.Connection constructor and there is a possibilty of the CnOpts constructor throwing a HostKeysException exception if no host keys are found resulting in the _cnopts attribute not being set.

Try the following updated code and let me know if it works:

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)
like image 195
Booboo Avatar answered Jan 03 '23 10:01

Booboo


I had the same problem. I solved this by disabling the hostkeys in the 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)
like image 30
toshin Avatar answered Jan 03 '23 10:01

toshin