Skip to main content

Async Mega.py

PyPI - Version PyPI - Python Version linting - Ruff GitHub License CI

Python library and CLI app for the Mega.nz and Transfer.it API

API Information

Supports:

  • Login (with credentials or creating a temporary account)
  • Upload
  • Download (files and folders)
  • Delete
  • Search
  • Export (public sharing)
  • Import public files to your account
  • Renaming
  • Moving files
  • Add/remove contacts
  • Get account stats (storage quota, transfer quota, balance (PRO accounts only))

TODO:

  • Support multifactor authentication (MFA) login

Please check src/mega/data_structures.py for details about the objects returned by the API

How To Use

from mega.client import MegaNzClient

email = "my_email@email.com"
password = "12345"
async with MegaNzClient() as mega:
    await mega.login(email, password)

Login should always be the first thing you do. Almost all operations require a valid account. You can call login without params to create a temporary account:

from mega.client import MegaNzClient

# Also works without using it as a context manager, but you have the responsability to close the session at the end
mega = MegaNzClient()
await mega.login()  # login using a temporary anonymous account
# await mega.close()

Methods

Check src/mega/client.py and src/mega/data_structures.pyto view the details of all public methods and which objects each one return.

The client deserializes the raw responses from the API and always returns dataclasses for objects (except for get_user which returns a normal dict)

# Get user details
# Includes email, user id, history of all emails, creation timestamp, etc...
await mega.get_user()

# Get account stats
# ex: Balance, storage quota, transfer quota, usage metrics, etc...
await mega.get_account_stats()

# Add/remove contacts
contact = "test@mega.nz"
await mega.add_contact(contact)
await mega.remove_contact(contact)


async def view_paths():
    fs = await mega.get_filesystem()
    print(fs.paths.values())


# Create a folder
await mega.create_folder("new_folder")
await mega.create_folder("new_folder/sub_folder/subsub_folder")
await view_paths()

# Rename a file or a folder
folder = await mega.find("new_folder/sub_folder/subsub_folder")
await mega.rename(folder, new_name="my_new_name")
await view_paths()

# Send this node to the trash bin (still counts towards your quota)
await mega.delete(folder.id)
await view_paths()

# This removes it completely from your account
await mega.destroy(folder.id)
await view_paths()

Upload / Downloads

# Upload a file, and get its public link
my_real_file = "/home/user/myfile.doc"  # Change this to a real file path!
uploaded_file = await mega.upload(my_real_file)  # Upload returns the Node that represents the file you just uploaded
await mega.export(uploaded_file)  # This only works with real accounts. Temp accounts can't create public links

# Download a file from your account
output_dir = "my downloads"
await mega.download(uploaded_file, output_dir)

# Download a public file
file_url = "https://mega.nz/file/vJ9EBJBC#vA1XpbngXcnN7lqXEWGQFPDc5ZlG6yltCHwGN-0O2LQ"
public_handle, public_key = mega.parse_file_url(file_url)
await mega.download_public_file(public_handle, public_key, output_dir)

# Download a public folder
folder_url = "https://mega.nz/folder/CJ8y1SDJ#KX8YfTd526P4o_hDH02jLQ"
public_handle, public_key, selected_node = mega.parse_folder_url(folder_url)
results = await mega.download_public_folder(public_handle, public_key, output_dir, selected_node)
for node_id, result in results.items():
    print((node_id, result))

# Import a file from URL
public_handle, public_key = mega.parse_file_url(file_url)
await mega.import_public_file(public_handle, public_key, dest_node_id=folder.id)

# How do you know if an URL is a file or folder?
result = mega.parse_url(url)
print(result.is_folder)
with mega.progress_bar:
    results = await mega.download_public_folder(public_handle, public_key, output_dir / "with_bar")

The filesystem object

The filesystem is a read only copy of your account's file structure.

# Get a read only copy of your filesystem
fs = await mega.get_filesystem()

# save a copy of your filesystem as json
import json
from pathlib import Path

dump = json.dumps(fs.dump(), indent=2, ensure_ascii=False)
Path("my_fs.json").write_text(dump)

What can the filesystem object do?

We are gonna use the example filesystem found at tests/fake_fs.json which has this structure:

"paths": {
    "qCZrYJVK": "/",
    "FeWnQouH": "/backup.sql",
    "coJ3yMOW": "/docker-compose.yml",
    "FzL3QdIj": "/Inbox",
    "2gL2GPaJ": "/index.html",
    "msinsVCj": "/logo.png",
    "MBlNlb2P": "/styles.css",
    "7N9QiWZ9": "/tests",
    "RDJJI2lv": "/tests/logo.png",
    "pHWVIQLd": "/tests/logo.png",
    "oImwb6nN": "/tests/script.js",
    "FIXitv4F": "/tests/scripts",
    "0fPFklV3": "/tests/scripts/notes.txt",
    "l9zkz1GU": "/tests/scripts/script.js",
    "E4LqT4EF": "/tests/scripts/styles.css",
    "i6ry53xV": "/tests/setup.sh",
    "Iri7NRCx": "/tests/utils.py",
    "2Tae8amE": "/Trash Bin",
    "t8HkzBH2": "/Trash Bin/data",
    "8EwHVJna": "/Trash Bin/data/docker-compose.yml"
  }

Read the filesystem from a file dump

from mega.filesystem import UserFileSystem

dump = Path("tests/fake_fs.json").read_text()
fs = UserFileSystem.from_dump(json.loads(dump))

# Search for nodes
query = "tests/script"
for node_id, path in fs.search(query):
    print(node_id)
    print(path)

# or
dict(fs.search(query))

The output will be:

{
  "oImwb6nN": "/tests/script.js",
  "FIXitv4F": "/tests/scripts",
  "0fPFklV3": "/tests/scripts/notes.txt",
  "l9zkz1GU": "/tests/scripts/script.js",
  "E4LqT4EF": "/tests/scripts/styles.css"
}
# Get the path to a node
fs.absolute_path("0fPFklV3")  # /tests/scripts/notes.txt

# Find a node by its *exact* path
result = fs.find("/tests/scripts/notes.txt")
print(result.id)  # "0fPFklV3"
# Get deleted files and folders (on the trash bin)
list(fs.deleted)

# List all the children of a folder (resursive)
folder = fs.find("/tests")
for node in fs.iterdir(folder.id, recursive=True):
    print(fs.absolute_path(node.id))

Output will be:

[
  "/tests/logo.png",
  "/tests/logo.png",
  "/tests/script.js",
  "/tests/scripts",
  "/tests/scripts/notes.txt",
  "/tests/scripts/script.js",
  "/tests/scripts/styles.css",
  "/tests/setup.sh",
  "/tests/utils.py"
]
fs.find("/tests/logo.png")  # This will fail
# You will have to call search and choose which one you actually want
dict(fs.search("/tests/logo.png"))

Transfer.it

from mega.transfer_it import TransferItClient

async with TransferItClient() as client:
    transfer_id = client.parse_url(url)
    # This is the same filesystem object as mega's,
    # but it does not have root, inbox or trash_bin nodes
    fs = await client.get_filesystem(transfer_id)
    output_dir = "My downloads"
    results = await client.download_transfer(transfer_id, output_dir)
    print(results)

CLI

You can use async-mega-py as a stand alone CLI app! Just install it with the optional [cli] dependencies. The CLI offers 2 commands: mega-py and async-mega-py. Both are just aliases for the same app.

# Install it with:
uv tool install async-mega-py[cli]

#Run it
mega-py --help
Usage: mega-py [OPTIONS] COMMAND [ARGS]...

 CLI app for the Mega.nz and Transfer.it. Set MEGA_EMAIL and MEGA_PWD
 enviroment variables to use them as credentials for Mega

╭─ Options ──────────────────────────────────────────────────────────────────────╮
│ --verbose  -v               Increase verbosity (-v shows debug logs,  -vv      │
│                             shows HTTP traffic)                                │
│ --help                      Show this message and exit.                        │
╰────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ─────────────────────────────────────────────────────────────────────╮
│ download   Download a public file or folder by its URL (transfer.it / mega.nz) │
│ dump       Dump a copy of your filesystem to disk                              │
│ stats      Show account stats                                                  │
│ upload     Upload a file to your account                                       │
╰────────────────────────────────────────────────────────────────────────────────╯

Metadata

Release files for async-mega.py 2.5.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for async-mega.py 2.5.1
File Size Uploaded Provenance Actions
async_mega_py-2.5.1.tar.gz 45.5 kB Without provenance Details for async_mega_py-2.5.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for async-mega.py 2.5.1
File Interpreter ABI Platform Actions
async_mega_py-2.5.1-py3-none-any.whl Python 3 none any Details for async_mega_py-2.5.1-py3-none-any.whl

Total release size: 95.1 kB

Release files / async_mega_py-2.5.1.tar.gz

Download URL async_mega_py-2.5.1.tar.gz
Size 45.5 kB
Tags Source
SHA-256 checksum
How to use checksums
2537d965d4e82c3a5184e67b3c330c4422a55740a872628b8a4ef6f4502cd6da
BLAKE2b-256 checksum
How to use checksums
62d8cfbab2591f23c7adc06f939b1a765de1e234b7b2927e01a6ed6c2dd76649
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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 / async_mega_py-2.5.1-py3-none-any.whl

Download URL async_mega_py-2.5.1-py3-none-any.whl
Size 49.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b65389f54cec37254495cfa8b18e41396e079288462f2e4906ef053c7bc854d3
BLAKE2b-256 checksum
How to use checksums
176b79b1267d1643c194f497024d933ae302612187b831ed6afe858b41ee5f82
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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}

Security for async-mega.py 2.5.1

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.

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