Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: [3.11, 3.13]
python-version: [3.11, 3.14]
fail-fast: true

defaults:
Expand All @@ -41,9 +41,8 @@ jobs:
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
uses: astral-sh/setup-uv@v10.2.0
with:
version: "0.10.11"
python-version: ${{ matrix.python-version }}

- name: Install dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
ref: ${{ github.ref_name }}
persist-credentials: false
- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
uses: astral-sh/setup-uv@v10.2.0
with:
enable-cache: false
- name: Ensure tag matches package version
Expand Down
14 changes: 4 additions & 10 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,8 @@ jobs:
with:
persist-credentials: false

- name: ruff lint
uses: astral-sh/ruff-action@v4.0.0
with:
version: "0.15.6"
args: "check --output-format=github"
- name: ruff
uses: astral-sh/ruff-action@v4.1.0

- name: ruff format check
uses: astral-sh/ruff-action@v4.0.0
with:
version: "0.15.6"
args: "format --check --diff"
- run: ruff format --check --diff --output-format github
if: ${{ !cancelled() }}
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ repos:
- id: detect-private-key
- id: end-of-file-fixer
- id: name-tests-test
args: [ --pytest-test-first ]
args: [--pytest-test-first]
- id: trailing-whitespace
args: [ --markdown-linebreak-ext=md ]
args: [--markdown-linebreak-ext=md]

- repo: https://github.com/pappasam/toml-sort
rev: v0.24.2
rev: v0.25.0
hooks:
- id: toml-sort-fix
files: ^(.*\.toml)$

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.6
rev: v0.16.10
hooks:
- id: ruff
args: [ --fix ]
args: [--fix]
- id: ruff-format
40 changes: 19 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ 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:
Expand All @@ -65,9 +64,8 @@ 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.login() # login using a temporary anonymous account
# await mega.close()

```

## Methods
Expand All @@ -93,18 +91,20 @@ 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())
print(fs.paths.values())


# Create a folder
await mega.create_folder('new_folder')
await mega.create_folder('new_folder/sub_folder/subsub_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')
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)
Expand All @@ -120,9 +120,9 @@ await view_paths()

```python
# 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
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"
Expand All @@ -138,15 +138,15 @@ 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))
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)
print(result.is_folder)
```

> [!TIP]
Expand Down Expand Up @@ -220,8 +220,8 @@ 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)
print(node_id)
print(path)

# or
dict(fs.search(query))
Expand All @@ -241,12 +241,11 @@ The output will be:

```python
# Get the path to a node
fs.absolute_path("0fPFklV3") # /tests/scripts/notes.txt
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"

print(result.id) # "0fPFklV3"
```

```python
Expand All @@ -257,7 +256,6 @@ list(fs.deleted)
folder = fs.find("/tests")
for node in fs.iterdir(folder.id, recursive=True):
print(fs.absolute_path(node.id))

```

Output will be:
Expand All @@ -282,7 +280,7 @@ Output will be:
> If 2 nodes have the same path, `find` will throw an error.

```python
fs.find("/tests/logo.png") # This will fail
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"))
```
Expand All @@ -302,7 +300,7 @@ async with TransferItClient() as client:
fs = await client.get_filesystem(transfer_id)
output_dir = "My downloads"
results = await client.download_transfer(transfer_id, output_dir)
print (results)
print(results)
```

## CLI
Expand Down
32 changes: 18 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "async-mega.py"
authors = [{name = "NTFSvolume", email = "NTFSvolume@proton.me"}]
authors = [{ name = "NTFSvolume", email = "NTFSvolume@proton.me" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
Expand All @@ -9,18 +9,18 @@ classifiers = [
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python"
"Programming Language :: Python :: 3.15"
]
dependencies = [
"aiohttp>=3.11.18",
"aiolimiter>=1.2.1",
"pycryptodome>=3.20.0"
"aiohttp>=3.14.0",
"aiolimiter>=1.3.0",
"pycryptodome>=3.24.0"
]
description = "Python library for the Mega.nz and Transfer.it API"
keywords = [
Expand All @@ -34,12 +34,12 @@ license = "Apache-2.0"
license-files = ["LICENSE"]
readme = "README.md"
requires-python = ">=3.11"
version = "2.4.1"
version = "2.5.0"

[project.optional-dependencies]
cli = [
"cyclopts>=4.10.1",
"python-dotenv>=1.2.1"
"cyclopts>=5.2.0",
"python-dotenv>=1.2.4"
]

[project.scripts]
Expand Down Expand Up @@ -114,17 +114,21 @@ sort_first = ["name", "project", "select", "tool"]
spaces_before_inline_comment = 2
spaces_indent_inline_array = 4

[tool.uv]
default-groups = "all"
required-version = ">=0.12.24"

[tool.uv.build-backend]
module-name = "mega"

[build-system]
build-backend = "uv_build"
requires = ["uv_build<=0.10.11"]
requires = ["uv_build>=0.12.24,<0.13.0"]

[dependency-groups]
dev = [
"prek>=0.4.0",
"pytest-asyncio>=0.25.0",
"pytest>=8.3.5",
"ruff==0.15.6"
"prek>=0.5.5",
"pytest-asyncio>=1.4.0",
"pytest>=9.1.1",
"ruff>=0.16.10,<0.17.0"
]
Loading
Loading