Metadata-Version: 2.4
Name: rclone
Version: 1.0.0
Summary: A robust, typed Python wrapper for the rclone CLI.
License-Expression: MIT
License-File: LICENSE
Keywords: rclone,cloud,storage,sync,backup,cli,wrapper
Author: Alyetama
Author-email: 56323389+Alyetama@users.noreply.github.com
Requires-Python: >=3.8
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Archiving :: Backup
Classifier: Topic :: System :: Filesystems
Classifier: Typing :: Typed
Provides-Extra: progress
Requires-Dist: tqdm (>=4.62) ; extra == "progress"
Project-URL: Homepage, https://github.com/Alyetama/rclone
Project-URL: Issues, https://github.com/Alyetama/rclone/issues
Project-URL: Repository, https://github.com/Alyetama/rclone
Description-Content-Type: text/markdown

# Rclone for Python

🚀 A robust, typed Python wrapper for [rclone](https://rclone.org).

[![Supported Python versions](https://img.shields.io/badge/Python-%3E=3.8-blue.svg)](https://www.python.org/downloads/)

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

- 🐍 [Python >= 3.8](https://www.python.org/downloads/)
- 📦 [rclone](https://rclone.org/downloads/) on your `PATH` (or pass `binary=...` / set `RCLONE_BINARY`)

## Installation

```sh
pip install rclone                # core, no third-party dependencies
pip install "rclone[progress]"    # adds tqdm for progress bars
```

## Quick start

```py
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

```py
# 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

```py
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:

```py
rc.ls("remote:/dir", "-R", "--max-depth", "2")
rc.copy("src/", "remote:/dst", "--transfers", "8", "--exclude", "*.tmp")
```

### Content helpers

```py
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:

```py
result = rc.run("dedupe", "remote:/dir", "--dedupe-mode", "newest")
print(result.returncode, result.stdout)
```

## Configuration

```py
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

```py
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 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

