user3848207
user3848207

Reputation: 4927

sftp file transfer using python works fine despite this ImportError. How to remove this error?

I have this python function to upload file through sftp. It works fine.

def sftp_upload(destination, username, password,
                     remote_loc, source_file):
    import pysftp
    with pysftp.Connection(destination, username,
                           password, log="pysftp.log") as sftp:
        sftp.cwd(remote_loc)
        sftp.put(source_file)

    sftp.close()
    return None

The code works as expected. However, I always receive this error at the end ImportError: sys.meta_path is None, Python is likely shutting down.

How to remove this error? I'm also puzzled why code runs smoothly to the end despite the error.

In the log file, I saw the following;

INF [20220304-18:49:14.727] thr=2   paramiko.transport.sftp: [chan 0] sftp session closed.
DEB [20220304-18:49:14.727] thr=2   paramiko.transport: [chan 0] EOF sent (0)
DEB [20220304-18:49:14.728] thr=1   paramiko.transport: EOF in transport thread

Here's the stack trace;

Exception ignored in: <function Connection.__del__ at 0x000001A8B08765E0>
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\pysftp\__init__.py", line 1013, in __del__
  File "C:\ProgramData\Anaconda3\lib\site-packages\pysftp\__init__.py", line 795, in close
ImportError: sys.meta_path is None, Python is likely shutting down

I am using python v3.9

Upvotes: 0

Views: 1350

Answers (2)

aaron
aaron

Reputation: 43103

Note: import pysftp outside the function somehow resolves the issue for me. 🤔


It's a bug in pysftp==0.2.9.

You can fix it by overriding close() to only run once:

class SFTPConnection(pysftp.Connection):
    def close(self):
        if getattr(self, '_closed', False):
            return
        self._closed = True
        super().close()

Usage:

# with pysftp.Connection(destination, username, password=password, log="pysftp.log") as sftp:  # -
with SFTPConnection(destination, username, password=password, log="pysftp.log") as sftp:       # +

References:

Upvotes: 2

guy szweigman
guy szweigman

Reputation: 554

It looks like your program ends before the sftp object is garbage-collected. Then, the sftp.__del__ method is called at the middle of the program's teardown, which is causing the error.

From pysftp.py code:

def __del__(self):
    """Attempt to clean up if not explicitly closed."""
    self.close()

I personally think that it should be considered as a bug in the pysftp project.

I can think of two workarounds:

  1. Override the __del__ method:

    pysftp.Connection.__del__ = lambda x: None

  2. (Less recomended - less efficient) Explicitly delete the sftp object and trigger garbage collection:

    del sftp; import gc; gc.collect() right after the with block

Upvotes: 1

Related Questions