A robust, typed Python wrapper for the rclone CLI.
Project description
Rclone for Python
🚀 A robust, typed Python wrapper for rclone.
It shells out to the rclone binary the safe way — every command is built as an
argument list and run without a shell, so paths and remote specs are
never re-interpreted. Common subcommands have explicit, typed methods that
return structured results; anything else is one run() call away.
Highlights
- 🔒 No shell, no injection. Arguments are passed as a list — never a shell string.
- 🧱 Zero required dependencies. Pure standard library.
tqdmis optional, only for progress bars. - 🧩 Typed API + structured results.
lsjson→list[dict],size→SizeResult, transfers →RcloneResult. - 📊 Reliable progress. Driven by rclone's own JSON stats log (works for remote destinations too), not by guessing file sizes.
- 💥 Real errors. Non-zero exits raise
RcloneCommandErrorcarrying the exit code, its meaning, and captured output.
Requirements
- 🐍 Python >= 3.8
- 📦 rclone on your
PATH(or passbinary=.../ setRCLONE_BINARY)
Installation
pip install rclone # core, no third-party dependencies
pip install "rclone[progress]" # adds tqdm for progress bars
Quick start
from rclone import Rclone
rc = Rclone() # finds rclone on PATH
rc.copy("foo.txt", "remote:/path/to/dst")
rc.ls("remote:/path/to/dir") # ['foo.bin', 'bar.txt', 'foo/']
rc.size("remote:/path/to/dir") # SizeResult(count=5, bytes=170397, sizeless=0)
The legacy import path still works:
from rclone.rclone import Rclone.
Examples
Transfers with progress
# A tqdm progress bar (requires the `progress` extra):
rc.copy("bigfile.bin", "remote:/backup", progress=True)
# Or your own callback, called on every stats tick:
def on_progress(stats):
print(f"{stats.percentage}% {stats.bytes}/{stats.total_bytes} {stats.speed:.0f} B/s")
result = rc.move("data/", "remote:/archive", progress=on_progress)
print(result.success, result.stats.bytes)
Listing and info
rc.lsjson("remote:/dir") # [{'Path': 'bar.txt', 'Name': 'bar.txt', 'Size': 0, 'IsDir': False}, ...]
size = rc.size("remote:/dir")
size.count, size.bytes # also: size.total_objects, size.total_size (legacy aliases)
rc.about("remote:") # {'total': ..., 'used': ..., 'free': ...}
rc.md5sum("remote:/dir") # {'bar.txt': 'd41d8cd9...'}
rc.listremotes() # ['gdrive:', 's3:']
rc.version() # 'v1.74.3'
Extra flags
Pass any rclone flags as positional arguments to any method:
rc.ls("remote:/dir", "-R", "--max-depth", "2")
rc.copy("src/", "remote:/dst", "--transfers", "8", "--exclude", "*.tmp")
Content helpers
text = rc.cat("remote:/notes.txt")
rc.rcat("remote:/notes.txt", "written from python") # reads from stdin
The escape hatch
Anything without a dedicated method is reachable via run() (returns an
RcloneResult) — arguments are still passed safely as a list:
result = rc.run("dedupe", "remote:/dir", "--dedupe-mode", "newest")
print(result.returncode, result.stdout)
Configuration
rc = Rclone(
binary="/usr/local/bin/rclone", # explicit path (else $RCLONE_BINARY, else PATH)
config="~/my-rclone.conf", # passed as --config
flags=["--fast-list"], # global flags applied to every command
debug=True, # log each command on the "rclone" logger
timeout=600, # seconds, for non-streaming commands
)
Error handling
from rclone import Rclone, RcloneCommandError
rc = Rclone()
try:
rc.copy("missing:", "remote:/dst")
except RcloneCommandError as exc:
print(exc.returncode) # e.g. 3
print(exc.stderr) # rclone's error output
# Or opt out of raising and inspect the result instead:
result = rc.check("a/", "b/") # check() does not raise on differences
if not result.success:
print("directories differ")
Migrating from 0.4.x
- Import is now
from rclone import Rclone(the oldfrom rclone.rclone import Rclonestill works). - The
unit=constructor argument is gone; the progress bar auto-scales units (B/KB/MB/GB). - Progress is opt-in per call via
progress=True(bar) orprogress=<callable>(callback) instead of being on by default. - Listing/size now return structured types (
list,SizeResult) and errors raiseRcloneCommandError. delete()works normally — the old artificial block is gone (the unsafe dynamic dispatch that motivated it was removed).execute("...")is still available; new code should preferrun(...).
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rclone-1.0.0.tar.gz.
File metadata
- Download URL: rclone-1.0.0.tar.gz
- Upload date:
- Size: 12.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.4.1 CPython/3.13.13 Darwin/25.5.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ffecbfe3ddf83a2a7fd66f6488bd7670ac782b72e7f528dfa1f90b820f323841
|
|
| MD5 |
84d3c2c4d2c03afd691d63cc31d830ee
|
|
| BLAKE2b-256 |
a9a4ee6e688a82babbead0a31141b659e8fd1470f59d908cb9aa04d2863926a2
|
File details
Details for the file rclone-1.0.0-py3-none-any.whl.
File metadata
- Download URL: rclone-1.0.0-py3-none-any.whl
- Upload date:
- Size: 12.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.4.1 CPython/3.13.13 Darwin/25.5.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f98f667f4e86b028fce0836fc1f0d2e10e94412164f42965d6dcdf1e4588a2d8
|
|
| MD5 |
98eab889f2e8f0ee3db4c08b1dfbcdff
|
|
| BLAKE2b-256 |
82dce6c9dad17d094fae9eff57b24626407e73bdd43a044ccf397b1d09c09ec3
|