pyludusavi
A robust, type-safe Python wrapper for the Ludusavi CLI.
Features
- Broad CLI Coverage: Supports the core Ludusavi subcommands and commonly used flags.
- Linux-First: Native support for both local binaries and Flatpak.
- Type-Safe: Comprehensive
TypedDictmodels for all JSON outputs (Python 3.12+). - Dual-Mode Execution: Transparently handles binary vs. Flatpak command prefixing.
- TDD-Backed: High-quality implementation with an extensive regression suite.
Setup
For local development, use the project wrapper so virtual environments and tool caches stay outside Dropbox:
source .envrc
./run.sh uv sync
Run validation through the same wrapper:
./run.sh uv run ruff check .
./run.sh uv run ty check src/
./run.sh uv run pytest
Installation
Use uv when adding the package to another Python project:
uv add pyludusavi
Quick Start
Basic Initialization
The wrapper automatically discovers Ludusavi via PATH or Flatpak.
from pyludusavi import Ludusavi
lud = Ludusavi()
print(f"Ludusavi version: {lud.version()}")
Backing Up Games
Perform a preview scan or a full backup.
# Preview a backup for a specific game
result = lud.backup(games=["The Witcher 3"], preview=True)
# Access typed data
for name, game in result.data["games"].items():
print(f"Game: {name}, Status: {game['change']}")
Searching for Games
Use Steam IDs or fuzzy matching to find games in the manifest.
# Find by Steam ID
result = lud.find(steam_id="292030")
# Use fuzzy matching
result = lud.find(games=["Witcher"], fuzzy=True)
Advanced Usage
Flatpak Support
If you have Ludusavi installed via Flatpak, pyludusavi detects it automatically. You can also specify a custom binary path or Flatpak ID:
lud = Ludusavi(explicit_path="/usr/bin/ludusavi")
lud = Ludusavi(flatpak_id="com.github.mtkennerly.ludusavi")
Custom Config Directory
lud = Ludusavi(config_dir="/home/user/my-ludusavi-config")
Custom Environment
Pass environment overrides when Ludusavi needs a different PATH, HOME, or
launcher-specific variable. Overrides are merged onto the current process environment
and used for both discovery and command execution.
lud = Ludusavi(env={"PATH": "/opt/ludusavi/bin:/usr/bin", "HOME": "/home/deck"})
Bulk API
For performance-critical bulk operations, use the native api subcommand:
payload = {
"requests": [
{"kind": "backup", "games": ["Game 1"]},
{"kind": "backup", "games": ["Game 2"]}
]
}
lud.bulk_api(payload)
Cloud Sync
Use the upload/download helpers with the same common options exposed by the CLI.
lud.cloud_upload(games=["The Witcher 3"], local="/backups", cloud="/cloud", preview=True)
lud.cloud_download(games=["The Witcher 3"], force=True)
Wrap Game Launch
Ludusavi requires either a direct game name or launcher inference when wrapping a command.
lud.wrap(["./game.exe", "--windowed"], name="The Witcher 3")
lud.wrap(["steam", "-applaunch", "292030"], infer="steam", force=True)
Game Aliases
get_game_alias(name) returns the manifest title a custom name is aliased to (or
None). Custom games / aliases are created in the Ludusavi GUI or config file; this
library reads them but does not write them.
lud.get_game_alias("My Game") # -> "The Witcher 3" or None
Timeouts
Quick, bounded commands (version, find, config_*, backups_list, schema,
complete) default to a 30-second timeout. Long-running operations — backup,
restore, wrap, cloud_upload, cloud_download, manifest_update, and bulk_api —
default to no timeout (timeout=None) so a long game session or large transfer is
not killed. Every one of these accepts an explicit timeout=<seconds> override. A
timeout raises LudusaviTimeoutError.
Note: The automatic background probe that verifies the Ludusavi executable during discovery has a fixed, non-configurable 15-second timeout. Timeout expiration rejects the candidate (falling back or raising LudusaviNotFoundError) rather than surfacing a timeout error.
# Wrap a game launch with no time limit (default)
lud.wrap(["./game.exe"], name="The Witcher 3")
# Cap a cloud upload at 5 minutes
lud.cloud_upload(games=["The Witcher 3"], timeout=300)
Reading Logs
Inspect Ludusavi's log directory and current log file:
lud.log_dir() # -> "/home/user/.config/ludusavi"
lud.log_show() # -> contents of ludusavi_rCURRENT.log, or "" if it does not exist
Error Handling
LudusaviNotFoundError: Raised if the executable or Flatpak isn't found.LudusaviExecutionError: Raised if the process exits with a non-zero code.LudusaviContractError: Raised if the CLI output is malformed or non-JSON when expected.LudusaviTimeoutError: Raised if the process exceeds its timeout. Subclass ofLudusaviError, so existingexcept LudusaviErrorhandlers still catch it.
Dependency Requirements
- Python 3.12+
- uv
- Ludusavi v0.31.0+
- pytest, pytest-cov, ruff, and ty for local development
License
MIT
Metadata
Release files for pyludusavi 0.3.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 | |
|---|---|---|---|
| pyludusavi-0.3.0.tar.gz | 12.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyludusavi-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.0 kB
Release files / pyludusavi-0.3.0.tar.gz
| Download URL | pyludusavi-0.3.0.tar.gz |
|---|---|
| Size | 12.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f0a0d64f10a5347de11e9c73f027ed06fa0c817be22cd39f5f321a5c1fe896dd
|
|
BLAKE2b-256 checksum How to use checksums |
86e2dbc2ddc99abe1a3f604e8202b4bcd5c37d1025cebe8aba8f8bc366467970
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / pyludusavi-0.3.0-py3-none-any.whl
| Download URL | pyludusavi-0.3.0-py3-none-any.whl |
|---|---|
| Size | 15.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4328381494371cb8cba5c40ee8bfb36641e852d52bb8aaaf7ca66e04fe1104c0
|
|
BLAKE2b-256 checksum How to use checksums |
2f5186435530e0de7765749f6713fae2a3ff73c3755529c45ea548d89ca11365
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|