Python pysftp upload using put_r fails with "Not a directory"

Question:

I’m trying to copy a file from my local to an SFTP but somehow I keep getting stuck in some error that I’m not able to fix.
I attach below the code I wrote since now taking as examples what I found here on Stack Overflow.

local_dir = '/local/dir'
local_file = 'test_file_sftp.csv'
localpath = os.path.join(local_dir, local_file)
remotepath = '/remote/path/'
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None

with pysftp.Connection(host='xx.xx.xx.xx',
                       username='some_name',
                       private_key='key',
                       cnopts=cnopts) as sftp:
    
    sftp.put_r(localpath, remotepath)
    print('Upload finished')

And this is the main error I wasn’t able to solve since now:

NotADirectoryError                        Traceback (most recent call last)
Input In [40], in <cell line: 12>()
     11 #set connection and put file into sftp
     12 with pysftp.Connection(host=host, username=username, private_key=private_key, cnopts=cnopts) as sftp:
---> 14     sftp.put_r(localpath, remotepath)
     15     print('- Upload finished!')

File /opt/anaconda3/envs/sky_roi/lib/python3.10/site-packages/pysftp/__init__.py:427, in Connection.put_r(self, localpath, remotepath, confirm, preserve_mtime)
    425 wtcb = WTCallbacks()
    426 cur_local_dir = os.getcwd()
--> 427 os.chdir(localpath)
    428 walktree('.', wtcb.file_cb, wtcb.dir_cb, wtcb.unk_cb)
    429 # restore local directory

NotADirectoryError: [Errno 20] Not a directory: '/Users/xyz/aaa/ab/cd/ef/test_file_sftp.csv'

I’m new to pysftp and SFTP in general, so any kind of hint will be greatly appreciated.

If I eliminate the file from the directory string localpath, the code works but it simply uploads the whole folder (obviously!) instead of the single file I want. Any advise on this? Maybe I’m missing something very basic and I’m not noticing it

Asked By: GLTCL

||

Answers:

As you can see here, to merge the path "/local/dir/" with the file "test_file_sftp" you dont need the "/" before the filename.

If you write "/test_file_sftp" looks like this file is in "/".

Try to test if your file exists in that directory:

#list the files in the path of the local_dir you provided
print(os.listdir(local_dir))
#list files in the current directory you are in:
dir_path = os.getcwd()
print(os.listdir(dir_path))

and then update the path according to that

Answered By: alphaBetaGamma

The Connection.put_r is for uploading folders. You are uploading a file, so use Connection.put. Though it requires a path to a remote file in the remotepath argument. So you need to add the filename:

local_dir = '/local/dir'
filename = 'test_file_sftp.csv'
localpath = os.path.join(local_dir, filename)
remote_dir = '/remote/path/'
remotepath = remote_dir + filename

sftp.put_r(local, remotepath)

Side notes:

Answered By: Martin Prikryl
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.