How to Create SFTP Functionality in Python

Olorunfemi Akinlua Feb 16, 2024
  1. Use pysftp to Create SFTP Functionality in Python
  2. Use paramiko to Create SFTP Functionality in Python
How to Create SFTP Functionality in Python

Secure Socket Shell (SSH) is a secure and better network protocol that allows us to access another computer and uses a password and public key authentication via SHA and encryption.

SSH File Transfer Protocol (SFTP) is a file transfer protocol that uses SSH and is better than the typical FTP that people previously used.

A file transfer protocol might be necessary for developing our application in Python. We should use the SFTP that gives us the default ability to overcome attacks such as password sniffing and man-in-the-middle and maintain our data integrity.

This article shows you how to use SFTP within your Python to move your data and files.

Use pysftp to Create SFTP Functionality in Python

Python comes with ftplib, an FTP client class with helper functions that provide the insecure FTP protocol service. For us to use SFTP, we need to install third-party libraries, and one of such libraries is the pysftp library.

With pysftp, you can access SFTP and work with the secure protocol to serve your application needs. To install pysftp, you need to use pip.

pip install pysftp

Also, we need an SFTP server. For Windows, we are going to use the WinSCP software, and to learn how to set up an SFTP server client on your Windows PC, you can go through this installation guide. However, if you have an SFTP server, let’s get started.

Before we write some code, we will log in to our SFTP server using our private key and the username (akinl) and hostname (localhost).

create sftp functionality in python - advanced site settings

Now, we are logged in to the root folder. Our goal will be to list the files and directory present within the root directory and copy files into the SFTP server, especially the store directory.

create sftp functionality in python - logged in sftp server

Let’s start coding using the pre-defined code template specified by the pysftp library. Within the code, we have assigned our hostname, port, username, and private key path.

These values are informed from your SFTP server details, and the private key is copied to the python file’s directory.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print("Connected to SFTP server!")

The above code connects to the SFTP server using an SFTP connection object (pysftp.Connection()) with the specified parameters. Inside the with block, we have an established SFTP connection within the object named sftp.

Following is an output of the code:

C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py:61: UserWarning: Failed to load HostKeys from C:\\Users\\akinl\\.ssh\\known_hosts. You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
  warnings.warn(wmsg, UserWarning)
Traceback (most recent call last):
  File "c:\\Users\\akinl\\Documents\\Python\\SFTP\\index.py", line 8, in <module>
    with pysftp.Connection(host=sftpHostName, port=sftpPort, username=userName, private_key=privateKeyPath) as sftp:
  File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 132, in __init__
    self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
  File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 71, in get_hostkey
    raise SSHException("No hostkey for host %s found." % host)
paramiko.ssh_exception.SSHException: No hostkey for host localhost found.
Exception ignored in: <function Connection.__del__ at 0x000001F0E9656320>
Traceback (most recent call last):
  File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 1013, in __del__
    self.close()
  File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 784, in close
    if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'

No hostkey for host %s found is a common error when working with SFTP connection objects with pysftp, which happens when the host file is not present.

To handle the issue, we can create connection options (pysftp.CnOpts()), specify that the host keys are None, and ignore the known hosts check.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print("SFTP server connection successful")

The output of the code is as follows:

C:\Python310\lib\site-packages\pysftp\__init__.py:61: UserWarning: Failed to load HostKeys from C:\Users\akinl\.ssh\known_hosts. You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
  warnings.warn(wmsg, UserWarning)
SFTP server connection successful

The only error we have is a low-level warning about the disabled host key checking. First, let’s change the working directory to show you we are within the SFTP server.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print("SFTP server connection successful")
    print("The current working directory is ", sftp.pwd)
    sftp.cwd("./store")
    print("After the cwd operation, the current working directory is ", sftp.pwd)

The above code’s output is given below:

SFTP server connection successful
The current working directory is /
After the cwd operation, the current working directory is /store.

The cwd changes the current working directory to what’s specified as its argument. Also, we can list the files within the root and store directories using the listdir() method and the files within the

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    rootFiles = sftp.listdir()
    storeFiles = sftp.listdir("./store")
    print(rootFiles, storeFiles)

The output of the code is as follows:

['index.txt', 'main.py', 'store'] []

The listdir() method lists all the files and directories within the current working directory if no argument is passed, but if we give an argument, it checks for files within the argument we pass. The result was two files and one directory for the root directory and none for the store directory because no file exists.

Now, let’s move some files into our SFTP server using some methods, put(), put_d(), and put_r(). We will use the put() to move only files.

Next, create a text file named test.txt within the same directory as our python file and copy the file into the SFTP server.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    sftp.put("test.txt", preserve_mtime=True)

The output of the code:

create sftp functionality in python - output

The test.txt file is now in the SFTP server root directory. Now, let’s move the same test.txt to the store directory and list its file content before and after copying it.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print(sftp.listdir("./store"))
    sftp.put("test.txt", preserve_mtime=True, remotepath="./store/upload.txt")
    print(sftp.listdir("./store"))

The above code’s output shows that the test.txt file was uploaded to the server as upload.txt and is visible within the image.

[]
['upload.txt']

create sftp functionality in python - upload output

We can copy a directory’s content using the put_d() method. For example, let’s create a SeptData directory containing three text files (one.txt, two.txt, and three.txt) and copy the directory content to the root folder.

However, for the path to copy from, we will need the full path, not the relative path we have used previously.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print(sftp.listdir("./"))
    sftp.put_d(
        r"C:\Users\akinl\Documents\Python\SFTP\SeptData", "./", preserve_mtime=True
    )
    print(sftp.listdir("./"))

The output of the code:

['index.txt', 'main.py', 'store', 'test.txt']
['index.txt', 'main.py', 'one.txt', 'store', 'test.txt', 'three.txt', 'two.txt']

The three files are now present within the root directory, as represented by the list of files and directories within the directory. Therefore, we can download files from the SFTP server using the get() method.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    sftp.get("./store/upload.txt", preserve_mtime=True)

After successfully running the code, the upload.txt file will be present within the directory of the python file. You can get remote directories using the get_d() and get_r() methods.

Use paramiko to Create SFTP Functionality in Python

Paramiko is a great library that provides a straightforward implementation of SSHv2 for Python via its classes and methods. We can use some of these methods to initiate connections to an SFTP server and work with that server via public key authentication.

To install paramiko, you can use the pip command as follows:

pip install paramiko

Using the connection details from the last section, we can carry out the same operations, from changing working directories to getting files from the remote SFTP server.

The SSHClient() creates a new SSH for us to connect to the SFTP server, and the set_missing_host_key_policy() allows us to set a policy for connecting to servers without a known host key, and the connect() method creates the actual connection to the SFTP server.

Let’s change the directory to the store directory and print the current working directory and the contents of the said directory with the help of chdir, getcwd, and listdir, respectively.

import paramiko

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(
    hostname=sftpHostName, port=sftpPort, username=userName, key_filename=privateKeyPath
)

sftp_client = ssh.open_sftp()
sftp_client.chdir("./store")
print(sftp_client.getcwd())
print(sftp_client.listdir())

sftp_client.close()
ssh.close()

The output of the code:

/store
['one.txt', 'three.txt', 'two.txt', 'upload.txt']

The first line contains the current working directory, which was set by the chdir() method, and the second line holds a list of the files and directories within the store directory.

Olorunfemi Akinlua avatar Olorunfemi Akinlua avatar

Olorunfemi is a lover of technology and computers. In addition, I write technology and coding content for developers and hobbyists. When not working, I learn to design, among other things.

LinkedIn