Is it possible to Remove Directory with some contents using pysftp module?

Question:

I am creating a backup script using pysftp module. I am able to upload
and download files. When i am trying to Delete a directory with some
contents i got an exception.

This is what i tried

con = pysftp.Connection('192.168.0.40',username='root',password='clado123')
con.chdir('/root/backup')
con.pwd
con.listdir()
['data', 'test']
data - directory is not empty.
test - directory is empty.
con.rmdir('test')
con.listdir()
['data']
con.rmdir('data')

OSError: Failure

Can any one suggest me a way to solve this problem?

Asked By: Fuji Komalan

||

Answers:

I have find out a way. There is method called ‘execute’ in the pysftp connection object. We can execute commands on remote server using this method.

con.execute('rm -rf /root/backup/data')
con.listdir()
[]
Answered By: Fuji Komalan

remove all the files from directory and then use rmdir to remove empty directory. Works for me.

def clean_dir(sftp, dir, files):
    assert sftp.isdir(str(dir)), "Outbox does not exist!"
    assert files.is_dir(), "Source directory does not exist!"
    for capsule in list(files.iterdir()):
        target = dir / capsule.name
        assert sftp.exists(str(target)), "Target files does not exist!"
        sftp.remove(str(target))
        assert not sftp.exists(str(target)), "Removed file still exists!"
Answered By: Alex

For a pysftp only approach to delete non-empty directories, you can use con.walktree to recursively delete all regular files while building a list of subdirectories to delete after the files.

You can’t directly delete the directories from walktree since it visits the deeper levels last, and you need the opposite.

After the walktree runs you can iterate (in reverse) over the list of directories and rmdir each one.

Note that in the code below fcallback=con.remove so walktree will call remove(remotepath) for each file recursively.

On the other hand, dcallback=dirs.append so for each directory will will execute dirs.append(directory_remote_path) , effectively building the list of directories to delete.

import os
import pysftp


sftp_host = os.environ[ 'SFTP_HOST' ]
sftp_username = os.environ[ 'SFTP_USERNAME' ]
sftp_password = os.environ[ 'SFTP_PASSWORD' ]

con = pysftp.Connection(sftp_host, username=sftp_username, password=sftp_password)

dirs = ['/root/backup/data']
con.walktree(dirs[0], fcallback=con.remove, dcallback=dirs.append, ucallback=con.remove, recurse=True)

print(dirs)

for d in reversed(dirs):
    print("Delete directory", d)
    con.rmdir(d)
    
con.close()

Answered By: RubenLaguna