Registry / http-networking / ftputil

ftputil

JSON →
library5.2.0pypypi✓ verified 84d ago

ftputil is a high-level FTP client library for the Python programming language. It implements a virtual file system for accessing FTP servers, providing many functions similar to those in the `os`, `os.path`, and `shutil` modules. It also offers convenience functions for conditional uploads and downloads, and handles FTP clients and servers in different timezones. The current stable version is 5.1.0, released on 2024-01-06. The project follows semantic versioning, with major version changes indicating backward incompatibility. Releases are announced on its mailing list.

pip install ftputil
INSTALL
IMPORT
SIG · FTPUTIL
F
ftputil
http-networkingpythonv5.2.0
Install
1.5s avg
Import
47ms
Disk
16MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v5.2.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.049s · 18.1MB
glibc
py 3.103.920 runs
installs and imports cleanly · install 1.5s · import 0.045s · 19MB
16MB installed
● package 16MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

FTPHost
from ftputil import FTPHost
import ftputil

This quickstart demonstrates how to connect to an FTP server, list files, download a file, create a remote directory, and upload a file using `ftputil.FTPHost`. It uses environment variables for credentials for security and easy testing.

import ftputil import os FTP_HOST = os.environ.get('FTP_HOST', 'ftp.example.com') FTP_USER = os.environ.get('FTP_USER', 'your_username') FTP_PASSWORD = os.environ.get('FTP_PASSWORD', 'your_password') # Example: Download files from the login directory with ftputil.FTPHost(FTP_HOST, FTP_USER, FTP_PASSWORD) as ftp_host: print(f"Connected to {FTP_HOST}. Current directory: {ftp_host.getcwd()}") names = ftp_host.listdir(ftp_host.curdir) for name in names: if ftp_host.path.isfile(name): print(f"Downloading {name}...") # remote name, local name ftp_host.download(name, name) # Example: Create a new directory and upload a file LOCAL_FILE_CONTENT = b"This is a test file.\n" LOCAL_FILE_NAME = "local_test.txt" REMOTE_DIR_NAME = "new_remote_dir" REMOTE_FILE_NAME = f"{REMOTE_DIR_NAME}/remote_test.txt" with open(LOCAL_FILE_NAME, 'wb') as f: f.write(LOCAL_FILE_CONTENT) with ftputil.FTPHost(FTP_HOST, FTP_USER, FTP_PASSWORD) as ftp_host: print(f"Creating remote directory {REMOTE_DIR_NAME}...") ftp_host.makedirs(REMOTE_DIR_NAME, exist_ok=True) print(f"Uploading {LOCAL_FILE_NAME} to {REMOTE_FILE_NAME}...") ftp_host.upload(LOCAL_FILE_NAME, REMOTE_FILE_NAME) print("Upload complete.") # Clean up local file os.remove(LOCAL_FILE_NAME)
Debug
Known issues
breakingftputil 4.0.0 changed the default behavior of the `DIR` command by no longer sending the `-a` option. This means 'hidden' files/directories (starting with a dot) are no longer included in listings by default, which may alter `listdir` or `walk` results.
fix
If hidden files are required, custom session factories or other workarounds may be needed, or consider explicit filtering if the server supports different `DIR` options.
affects: >=4.0.0
breakingThe definition of 'time shift' used for `upload_if_newer` and `download_if_newer` changed in ftputil 4.0.0. Previously it was `server_time - local_client_time`; now it's defined as `server_listing_time - UTC`. This is backward-incompatible and may require adjusting existing code, especially if `synchronize_times` or explicit `set_time_shift` calls are used.
fix
Review and adjust time shift calculations or call `ftp_host.synchronize_times()` to ensure correct time synchronization between client and server.
affects: >=4.0.0
breakingftputil 5.0.0 is not backward-compatible with 4.0.0 and earlier due to compatibility changes with `ftplib` in Python 3.9. This primarily affects internal workings and session factory implementations.
fix
Upgrade to the latest 5.x.x version and test thoroughly. If using custom `session_factory` implementations, review against Python 3.9+ `ftplib` changes.
affects: 5.0.0
gotchaCalling `isdir`, `isfile`, or `islink` on path names returned by `listdir` can incorrectly return `False` if the `listdir` call was not for the current directory. This happens because these methods expect a full path or a path relative to the current working directory of the `FTPHost` instance.
fix
Always construct full paths using `ftp_host.path.join(parent_path, name)` before passing them to `isdir`, `isfile`, `islink`, or similar methods if the `name` isn't from `ftp_host.curdir`.
affects: All
gotchaThe `FTPHost.lstat('/')` method (for the root directory) will raise a `RootDirError`. This is a known limitation of the underlying algorithm. You can `stat` items *in* the root directory, but not the root directory itself.
fix
Avoid calling `lstat` directly on the root path '/'. For checks on the root, use `listdir('/')` to see its contents instead.
affects: All
gotchaThe methods `upload_if_newer` and `download_if_newer` may behave unexpectedly (e.g., unnecessary transfers or failing to transfer) due to subtle differences in server timestamp precision (often only to the minute) or incorrect time zone synchronization between the client and server.
fix
Ensure correct time zone synchronization using `ftp_host.synchronize_times()`. Be aware that if timestamps are only minute-precise, ftputil errs on the side of transferring too much data. For interrupted transfers, consider using `upload`/`download` directly or explicitly removing the incomplete remote file before retrying `upload_if_newer`.
affects: All
Upgrade
Version history
5.2.0latest on PyPI · released Apr 25, 2026
Audit
Dependencies

No dependency data recorded yet.

Agent activity
16 hits · last 30 days
node
14
OpenAI (training)
1
Resources
ftputil — pip install ftputil · libregistry