resources/send_message_and_files/ftp.py

This module provides a high-level interface for sending files to the FTP server in a form of FTPClient class.

When initializing an instance of the class (if parameter check_connection = True), it tries to connect to the ftp server and will cause an error if the connection failed.

If at the start of the script this check was successful - no errors will be caused - the script will automatically try to reconnect.

The class keeps only one connection active at the same time. The connection is closed after the transfer.

All files that are sent by the FTPClient.send method are added to the queue. Then, in a separate thread, the worker of sending files from the queue starts.

The logic is something like this:

  1. We take the first file from the queue;
  2. Trying to send it;
  3. If the ftplib.all_errors error occurred while sending, the file is returned to the end of the queue and status.ftp_error is passed to the callback ;
  4. If another error is occurred, the file is not returned to the queue, and status.error is returned to the callback ;
  5. If the file has been successfully sent, status.success is passed to the callback ;
  6. Back to the first point (taking the next file).

Class attributes

  • host (str): FTP server address.
  • port (int, optional): FTP server port, 21 by default.
  • user (str, optional): FTP user name. anonymous by default.
  • passwd (str, optional): FTP user password. Empty string by default.
  • work_dir (str, optional)Folder on the ftp server where all files will be sent. If not specified, all files are sent to the ftp root directory.
  • callback (callable[str, str])Callback function where the guid and task status are passed.
  • queue_maxlen (int, optional)The maximum length of the transfer queue. 1000 by default.
  • check_connection (bool, optional)If True - checks the connection at initialization. Raises CheckConnectionError if no connection is available. True by default.

Class methods

  • check_connection() - Checks the connection to the server. Raises CheckConnectionError if no connection is available.
  • send(file_path, remote_dir=None, callback=None, task_guid=None)Sets up a task for sending to the ftp server. Returns the task guid.
    Method arguments:
    • file_path (str)Full path to the file to be uploaded.
    • remote_dir (str, optional)The folder on the remote server where you need to save the file. If the work_dir parameter is set, then it is also taken into account when sending a file.
    • callback (callable[str, str])Callback function, where the guid and task status are passed. If not set, the function passed to the callback parameter of the class is used.
    • task_guid (str): Task guid. By default, it is set using the function host.random_guid() .

File upload statuses

Possible file upload statuses are contained in the status object:

  • status.sending File is being sent.
  • status.error File sending error.
  • status.ftp_error FTP connection error.
  • status.success - File has been sent successfully.
  • status.in_queue The file has been added to the send queue.

Code examples

Tracking the file upload status

When initializing the class, you can specify the callback function that will be called during the file transfer process.
The function takes two arguments:

  • task_guid (str) - Task guid (also returned when calling the transfer function).
  • state (str)- Current status of the file transfer.
import os
import host
from ftp import FTPClient, status

tasks = {}


def callback(task_guid, state):
    popup = host.error
    if state == status.success or state == status.in_queue:
        popup = host.message
    elif state == status.sending:
        popup = host.alert
    popup("%s: %s" % (task_guid, state))
    
    if state == status.success:
        os.remove(tasks[task_guid])


client = FTPClient("localhost", port=21, user="trassir", passwd="12345", callback=callback)

file_to_send = "../file1.txt"
task_guid = client.send("../file1.txt")
tasks[task_guid] = file_to_send
Sending files to different directories

If you need to send files to different directories - DO NOT CREATE DIFFERENT CLASS INSTANCES. The global directory in which the script will run can be set for the class. A separate directory for each file can be set as well. Global one is set during the class initialization - using the work_dir argument. When sending a file, the FTPClient.send method can take an optional remote_dir argument.

Sending files to FTP root

ftp
│ file1.txt
│ file2.txt

from ftp import FTPClient

client = FTPClient("localhost", port=21, user="trassir", passwd="12345")
client.send("../file1.txt")
client.send("../file2.txt")
Sending all files to mypath directory
ftp
└───mypath
    │   file1.txt
    │   file2.txt
from ftp import FTPClient

client = FTPClient("localhost", port=21, user="trassir", passwd="12345", work_dir="mypath")
client.send("../file1.txt")
client.send("../file2.txt")
Sending each file to a different directory
ftp
└───file1_dir
│   │   file1.txt
│   
└───file2_dir
    └───subdir
        │   file2.txt
from ftp import FTPClient

client = FTPClient("localhost", port=21, user="trassir", passwd="12345")
client.send("../file1.txt", remote_dir="file1_dir")
client.send("../file2.txt", remote_dir="file2_dir/subdir")
Complex directory hierarchy

We will use the script_path folder on the FTP server and at the same time, inside this folder, we will create different folders for each file.

ftp
└───script_path
    └───file1_dir
    |   │ file1.txt
    └───file2_dir
        └───subdir
            | file2.txt

from ftp import FTPClient

client = FTPClient("localhost", port=21, user="trassir", passwd="12345", work_dir="script_path")


client.send("../file1.txt", remote_dir="file1_dir")
client.send("../file2.txt", remote_dir="file2_dir/subdir")


  • Нет меток