Skip to main content

Rclone for Python

🚀 A robust, typed Python wrapper for rclone.

Supported Python versions

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. tqdm is 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 RcloneCommandError carrying the exit code, its meaning, and captured output.

Requirements

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() and lsl() now return a list[Entry] (structured: name, size, mod_time, is_dir, count, raw) instead of a list[str] of raw rclone lines. Use [e.name for e in rc.lsd(path)] for just names, or ls() which already returns names.

Migrating from 0.4.x

  • Import is now from rclone import Rclone (the old from rclone.rclone import Rclone still 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) or progress=<callable> (callback) instead of being on by default.
  • Listing/size now return structured types (list, SizeResult) and errors raise RcloneCommandError.
  • 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 prefer run(...).

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)

Source distribution for rclone 2.0.0
File Size Uploaded
rclone-2.0.0.tar.gz 13.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rclone 2.0.0
File Interpreter ABI Platform
rclone-2.0.0-py3-none-any.whl Python 3 none any Details

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

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files

1.0.0

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3

2 release files

0.2

2 release files

0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page