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.ls("remote:/dir") # ['bar.txt', 'foo/'] (names only)
rc.lsjson("remote:/dir") # [{'Path': 'bar.txt', 'Name': 'bar.txt', 'Size': 0, 'IsDir': False}, ...]
# lsd (directories) and lsl (files) return structured Entry objects:
rc.lsd("remote:/dir") # [Entry(name='sub', size=128, mod_time=datetime(...), is_dir=True, count=-1), ...]
rc.lsl("remote:/dir") # [Entry(name='bar.txt', size=11, mod_time=datetime(...), is_dir=False), ...]
for entry in rc.lsd("remote:/dir"):
print(entry.name, entry.size, entry.mod_time)
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 to 2.0
lsd()andlsl()now return alist[Entry](structured:name,size,mod_time,is_dir,count,raw) instead of alist[str]of raw rclone lines. Use[e.name for e in rc.lsd(path)]for just names, orls()which already returns names.
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
Metadata
Release files for rclone 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| rclone-2.0.0.tar.gz | 13.3 kB | Without provenance | Details for rclone-2.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| rclone-2.0.0-py3-none-any.whl | Python 3 | none | any | Details for rclone-2.0.0-py3-none-any.whl |
Total release size: 26.2 kB
Release files / rclone-2.0.0.tar.gz
| Download URL | rclone-2.0.0.tar.gz |
|---|---|
| Size | 13.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
145698f95759af6efe915e72a8927c6f734cf9b4a5f5252c3771891b8f0098f5
|
|
BLAKE2b-256 checksum How to use checksums |
c44fe6d5dd6d518c5155ee0d75cf4e284f9e90204953ac32047a7f505c29b72c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.13.13 Darwin/25.5.0
|
Release files / rclone-2.0.0-py3-none-any.whl
| Download URL | rclone-2.0.0-py3-none-any.whl |
|---|---|
| Size | 12.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
031606b643789a61743dc9eb4ad5c686f668453e04683c76bc4ecf3af7bd46e9
|
|
BLAKE2b-256 checksum How to use checksums |
a32054cfd1fdd98b759e38ef5dd2ecb5dc3c6bc5ab5c0920ff3f58b0c81524e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.13.13 Darwin/25.5.0
|
Security for rclone 2.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.