A modern, type-safe Python wrapper around the aria2c download utility with a clean local CLI experience and batteries-included JSON-RPC client.
- Python 3.9+
aria2cavailable on yourPATH
Install aria2c first (examples show macOS and Debian/Ubuntu, adapt as needed):
# macOS
brew install aria2
# Debian/Ubuntu
sudo apt install aria2Install the latest release from PyPI:
pip install aria2pyTo try the bleeding-edge version straight from GitHub:
pip install git+https://github.com/omar-hanafy/aria2py.gitfrom aria2py import Aria2Client
client = Aria2Client()
result = client.download("https://example.com/file.zip")
print(result.stdout)download() returns subprocess.CompletedProcess, so stdout/stderr and the exit code are readily available. Set stream=True to mirror aria2c’s live console output:
client.download("https://example.com/file.zip", stream=True)fetch() inspects the target and dispatches automatically:
client.fetch("https://example.com/file.zip") # HTTP/S
client.fetch("magnet:?xt=urn:btih:...") # Magnet links
client.fetch("https://example.com/file.torrent")
client.fetch("downloads.meta4")
client.fetch(["https://mirror/a", "https://mirror/b"]) # Multiple URIsIf a local text file is passed, the path is emitted as --input-file=....
Every aria2c switch maps to a typed field. Combine option groups to tailor the command:
from aria2py import Aria2Client, BasicOptions, HttpOptions
client = Aria2Client(
basic_options=BasicOptions(
dir="/tmp/downloads",
continue_download=True,
),
http_options=HttpOptions(
header=["User-Agent: aria2py"],
retry_wait=5,
max_tries=3,
),
)
client.fetch("https://example.com/bundle.zip")Validation runs before any process is spawned, surfacing typos (bad enums, negative values, etc.) immediately.
from aria2py import Aria2Client, BitTorrentOptions, MetalinkOptions
client = Aria2Client(
bt_options=BitTorrentOptions(enable_dht=True, seed_ratio=1.0),
metalink_options=MetalinkOptions(select_file="1-5", show_files=True),
)
client.download_magnet("magnet:?xt=urn:btih:...")
client.download_torrent("/path/to/file.torrent")
client.download_metalink("/path/to/file.meta4")MetalinkOptions exposes dedicated select_file / show_files shims so you no longer need to reach into the BitTorrent option set for file selection.
from aria2py import Aria2Client, RpcOptions
client = Aria2Client(
rpc_options=RpcOptions(
enable_rpc=True,
rpc_listen_port=6800,
rpc_secret="my-secret-token",
)
)
with client: # starts aria2c with RPC enabled
print(client.rpc.get_version())
# ... perform RPC calls ...The context manager ensures the aria2c process terminates cleanly when you exit the block. You can also call start_rpc_server() yourself; repeated calls are idempotent while the process is running.
To connect to an already running aria2c instance, disable the local binary requirement:
remote = Aria2Client(
rpc_options=RpcOptions(enable_rpc=True, rpc_listen_port=6800, rpc_secret="token"),
require_local_binary=False,
)
print(remote.rpc.get_version())High-level helpers translate Python keyword arguments into aria2-compatible option dictionaries:
from aria2py import Aria2Client, BasicOptions, RpcOptions
client = Aria2Client(
basic_options=BasicOptions(dir="/data"),
rpc_options=RpcOptions(enable_rpc=True, rpc_secret="token"),
require_local_binary=False,
)
gid = client.add("https://example.com/archive.zip")
client.pause(gid)
client.resume(gid)
status = client.status(gid, keys=["status", "completedLength", "downloadSpeed"])
queue = client.waiting(offset=0, num=50)
stopped = client.stopped(offset=0, num=50)
stats = client.rpc.get_global_stat()
client.set_options(gid, max_download_limit="500K")
client.set_global(max_overall_download_limit="5M", enable_color=False)Torrent and metalink payloads can be uploaded without manual base64 encoding:
client.add_torrent_rpc("ubuntu.torrent", uris=["https://mirror.example/ubuntu.iso"])
client.add_metalink_rpc("downloads.meta4")Errors coming back from aria2 are raised as Aria2RpcError so you can handle them cleanly:
from aria2py.exceptions import Aria2RpcError
try:
client.pause("0000000000000000")
except Aria2RpcError as exc:
print(exc.code, exc)If you need lower-level control, the underlying Aria2RpcClient is available via client.rpc and supports every helper directly (add_uri, tell_active, remove_download_result, purge_download_result, and more).
aria2c understands the classic Netscape cookie jar format (the one Firefox/Chrome export). Point HttpOptions.load_cookies at your cookies.txt to replay authenticated sessions:
from aria2py import Aria2Client, BasicOptions, HttpOptions
client = Aria2Client(
basic_options=BasicOptions(dir="/tmp/downloads"),
http_options=HttpOptions(
load_cookies="/tmp/cookies.txt", # use exported browser cookies
save_cookies="/tmp/cookies-refreshed.txt" # optional: persist updates from aria2c
),
)
client.fetch("https://example.com/private/file.zip")The same configuration flows through JSON-RPC calls (add, add_torrent_rpc, set_options, etc.), so downloads launched remotely pick up identical cookie headers. Paths must be accessible to the aria2c process, so prefer absolute locations.
When you pass stream=True to any download method (download, download_magnet, fetch, etc.) aria2py invokes aria2c with stdout/stderr wired to your terminal, mirroring the native CLI experience—handy when you want to monitor progress without parsing output.
Custom exceptions provide actionable feedback:
Aria2NotInstalledError– aria2c is missing on the host.Aria2CommandError– local process exited non-zero; includes stdout/stderr for debugging.Aria2RpcError– JSON-RPC error response with structured code/message/data attributes.
Example:
from aria2py import Aria2Client, RpcOptions
from aria2py.exceptions import Aria2CommandError, Aria2NotInstalledError, Aria2RpcError
client = Aria2Client(require_local_binary=False, rpc_options=RpcOptions(enable_rpc=True))
try:
client.fetch("https://example.com/file.zip")
except Aria2NotInstalledError:
print("Install aria2c before running local downloads.")
except Aria2CommandError as exc:
print(f"aria2c failed: {exc.stderr}")
except Aria2RpcError as exc:
print(f"RPC error {exc.code}: {exc}")The repository ships with a growing unit test suite that exercises option conversion, dispatch logic, RPC payloads, and process lifecycle. Run everything with:
pytest
# or
python -m unittest discoverOption classes mirror the aria2 manual and are tracked in docs/option_coverage.md. Each dataclass groups related switches:
BasicOptionsHttpOptionsBitTorrentOptionsMetalinkOptionsRpcOptionsAdvancedOptions
Because the models are plain dataclasses, IDE auto-complete and static typing tools (mypy/pyright) work out of the box.
aria2py is released under the MIT License. See LICENSE for details.