async-mega-py 2.0.3.dev0__tar.gz → 2.0.4.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/PKG-INFO +1 -1
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/pyproject.toml +1 -1
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/client.py +3 -3
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/progress.py +53 -35
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/transfer_it.py +3 -3
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/utils.py +3 -3
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/LICENSE +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/README.md +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/__init__.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/__main__.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/api.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/auth.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/chunker.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/cli/__init__.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/cli/app.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/core.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/crypto.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/data_structures.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/download.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/env.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/errors.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/filesystem.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/py.typed +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/upload.py +0 -0
- {async_mega_py-2.0.3.dev0 → async_mega_py-2.0.4.dev0}/src/mega/vault.py +0 -0
|
@@ -22,7 +22,7 @@ from mega.crypto import (
|
|
|
22
22
|
from mega.data_structures import AccountStats, Attributes, Crypto, FileInfo, Node, NodeID, NodeType, UserResponse
|
|
23
23
|
from mega.download import DownloadResults
|
|
24
24
|
from mega.filesystem import FileSystem
|
|
25
|
-
from mega.utils import Site,
|
|
25
|
+
from mega.utils import Site, async_map
|
|
26
26
|
|
|
27
27
|
from .errors import MegaNzError, RequestError, ValidationError
|
|
28
28
|
|
|
@@ -207,7 +207,7 @@ class MegaNzClient(MegaCore):
|
|
|
207
207
|
base_path = Path(output_dir or ".")
|
|
208
208
|
folder_url = f"{_DOMAIN}/folder/{public_handle}#{public_key}"
|
|
209
209
|
|
|
210
|
-
async def
|
|
210
|
+
async def download(file: Node) -> tuple[NodeID, Path | Exception]:
|
|
211
211
|
web_url = folder_url + f"/file/{file.id}"
|
|
212
212
|
output_path = base_path / fs.relative_path(file.id)
|
|
213
213
|
try:
|
|
@@ -224,7 +224,7 @@ class MegaNzClient(MegaCore):
|
|
|
224
224
|
|
|
225
225
|
return file.id, result
|
|
226
226
|
|
|
227
|
-
results = await
|
|
227
|
+
results = await async_map(download, fs.files_from(root_id))
|
|
228
228
|
return DownloadResults.split(dict(results))
|
|
229
229
|
|
|
230
230
|
async def upload(self, file_path: str | PathLike[str], dest_node_id: NodeID | None = None) -> Node:
|
|
@@ -3,14 +3,16 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import contextlib
|
|
5
5
|
from contextvars import ContextVar
|
|
6
|
-
from typing import TYPE_CHECKING, Any, Literal, Protocol, TypeAlias
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Literal, Protocol, TypeAlias, TypeVar
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from collections.abc import Callable, Generator
|
|
10
10
|
from types import TracebackType
|
|
11
11
|
|
|
12
|
-
from rich.progress import Progress
|
|
12
|
+
from rich.progress import Progress, Task
|
|
13
|
+
from rich.text import Text
|
|
13
14
|
|
|
15
|
+
_T = TypeVar("_T")
|
|
14
16
|
ProgressHook: TypeAlias = Callable[[float], None]
|
|
15
17
|
|
|
16
18
|
class ProgressHookContext(Protocol):
|
|
@@ -33,12 +35,13 @@ current_hook: ContextVar[ProgressHook] = ContextVar("current_hook", default=lamb
|
|
|
33
35
|
|
|
34
36
|
|
|
35
37
|
@contextlib.contextmanager
|
|
36
|
-
def
|
|
37
|
-
|
|
38
|
+
def _enter_context(context_var: ContextVar[_T], value: _T) -> Generator[None]:
|
|
39
|
+
"""Context manager for context vars"""
|
|
40
|
+
token = context_var.set(value)
|
|
38
41
|
try:
|
|
39
42
|
yield
|
|
40
43
|
finally:
|
|
41
|
-
|
|
44
|
+
context_var.reset(token)
|
|
42
45
|
|
|
43
46
|
|
|
44
47
|
@contextlib.contextmanager
|
|
@@ -48,12 +51,8 @@ def new_task(description: str, total: float, kind: Literal["UP", "DOWN"]) -> Gen
|
|
|
48
51
|
yield
|
|
49
52
|
return
|
|
50
53
|
|
|
51
|
-
with factory(description, total, kind) as
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
yield
|
|
55
|
-
finally:
|
|
56
|
-
current_hook.reset(token)
|
|
54
|
+
with factory(description, total, kind) as new_hook, _enter_context(current_hook, new_hook):
|
|
55
|
+
yield
|
|
57
56
|
|
|
58
57
|
|
|
59
58
|
@contextlib.contextmanager
|
|
@@ -66,45 +65,64 @@ def new_progress() -> Generator[None]:
|
|
|
66
65
|
def hook_factory(*args, **kwargs):
|
|
67
66
|
return _new_rich_task(progress, *args, **kwargs)
|
|
68
67
|
|
|
69
|
-
with
|
|
68
|
+
with (
|
|
69
|
+
progress,
|
|
70
|
+
_enter_context(_PROGRESS_HOOK_FACTORY, hook_factory),
|
|
71
|
+
):
|
|
70
72
|
yield
|
|
71
73
|
|
|
72
74
|
|
|
73
|
-
def _truncate_desc(desc: str, length: int = 80, placeholder: str = "...") -> str:
|
|
74
|
-
if len(desc) <= length:
|
|
75
|
-
return desc
|
|
76
|
-
|
|
77
|
-
return f"{desc[: length - len(placeholder)]}{placeholder}"
|
|
78
|
-
|
|
79
|
-
|
|
80
75
|
def _new_rich_progress() -> Progress | None:
|
|
81
76
|
try:
|
|
77
|
+
from rich import get_console
|
|
82
78
|
from rich.progress import (
|
|
83
79
|
BarColumn,
|
|
84
80
|
DownloadColumn,
|
|
85
81
|
Progress,
|
|
86
82
|
SpinnerColumn,
|
|
83
|
+
TextColumn,
|
|
87
84
|
TimeRemainingColumn,
|
|
88
85
|
TransferSpeedColumn,
|
|
89
86
|
)
|
|
87
|
+
from rich.table import Column
|
|
90
88
|
except ImportError:
|
|
91
89
|
return None
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
)
|
|
91
|
+
console = get_console()
|
|
92
|
+
|
|
93
|
+
class AutoTruncatedTextColumn(TextColumn):
|
|
94
|
+
def render(self, task: Task) -> Text:
|
|
95
|
+
text = super().render(task)
|
|
96
|
+
width = console.width
|
|
97
|
+
available_witdh = min((width * 60 // 100), (width - 65))
|
|
98
|
+
desc_limit = max(available_witdh, 8)
|
|
99
|
+
text.truncate(desc_limit, overflow="ellipsis")
|
|
100
|
+
return text
|
|
101
|
+
|
|
102
|
+
return Progress(
|
|
103
|
+
"[{task.fields[kind]}]",
|
|
104
|
+
SpinnerColumn(),
|
|
105
|
+
AutoTruncatedTextColumn("{task.description}"),
|
|
106
|
+
BarColumn(
|
|
107
|
+
bar_width=None,
|
|
108
|
+
),
|
|
109
|
+
"[progress.percentage]{task.percentage:>6.1f}%",
|
|
110
|
+
"•",
|
|
111
|
+
DownloadColumn(
|
|
112
|
+
table_column=Column(justify="right", no_wrap=True),
|
|
113
|
+
),
|
|
114
|
+
"•",
|
|
115
|
+
TransferSpeedColumn(table_column=Column(justify="right", no_wrap=True)),
|
|
116
|
+
"•",
|
|
117
|
+
TimeRemainingColumn(
|
|
118
|
+
compact=True,
|
|
119
|
+
elapsed_when_finished=True,
|
|
120
|
+
table_column=Column(justify="right", no_wrap=True),
|
|
121
|
+
),
|
|
122
|
+
transient=True,
|
|
123
|
+
console=console,
|
|
124
|
+
expand=True,
|
|
125
|
+
)
|
|
108
126
|
|
|
109
127
|
|
|
110
128
|
@contextlib.contextmanager
|
|
@@ -114,7 +132,7 @@ def _new_rich_task(
|
|
|
114
132
|
total: float,
|
|
115
133
|
kind: Literal["UP", "DOWN"],
|
|
116
134
|
) -> Generator[ProgressHook]:
|
|
117
|
-
task_id = progress.add_task(
|
|
135
|
+
task_id = progress.add_task(description, total=total, kind=kind)
|
|
118
136
|
|
|
119
137
|
def progress_hook(advance: float) -> None:
|
|
120
138
|
progress.advance(task_id, advance)
|
|
@@ -15,7 +15,7 @@ from mega.crypto import b64_to_a32, b64_url_decode, decrypt_attr
|
|
|
15
15
|
from mega.data_structures import Attributes, Crypto, Node, NodeID, NodeType
|
|
16
16
|
from mega.download import DownloadResults
|
|
17
17
|
from mega.filesystem import FileSystem
|
|
18
|
-
from mega.utils import Site,
|
|
18
|
+
from mega.utils import Site, async_map
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
21
|
from collections.abc import Iterable
|
|
@@ -107,7 +107,7 @@ class TransferItClient(AbstractApiClient):
|
|
|
107
107
|
base_path = Path(output_dir or ".") / f"transfer.it ({transfer_id})"
|
|
108
108
|
folder_url = f"https://transfer.it/t/{transfer_id}"
|
|
109
109
|
|
|
110
|
-
async def
|
|
110
|
+
async def download(file: Node) -> tuple[NodeID, Path | Exception]:
|
|
111
111
|
web_url = folder_url + f"#{file.id}"
|
|
112
112
|
output_path = base_path / fs.relative_path(file.id)
|
|
113
113
|
dl_link = self.create_download_url(transfer_id, file)
|
|
@@ -123,7 +123,7 @@ class TransferItClient(AbstractApiClient):
|
|
|
123
123
|
|
|
124
124
|
return file.id, result
|
|
125
125
|
|
|
126
|
-
results = await
|
|
126
|
+
results = await async_map(download, fs.files_from(root_id))
|
|
127
127
|
return DownloadResults.split(dict(results))
|
|
128
128
|
|
|
129
129
|
async def _download_file(self, dl_link: str, output_path: str | PathLike[str]) -> Path:
|
|
@@ -77,7 +77,7 @@ def transform_v1_url(url: yarl.URL) -> yarl.URL:
|
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
@overload
|
|
80
|
-
async def
|
|
80
|
+
async def async_map(
|
|
81
81
|
coro_factory: Callable[[_T1], Awaitable[_T2]],
|
|
82
82
|
values: Iterable[_T1],
|
|
83
83
|
*,
|
|
@@ -87,7 +87,7 @@ async def throttled_gather(
|
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
@overload
|
|
90
|
-
async def
|
|
90
|
+
async def async_map(
|
|
91
91
|
coro_factory: Callable[[_T1], Awaitable[_T2]],
|
|
92
92
|
values: Iterable[_T1],
|
|
93
93
|
*,
|
|
@@ -96,7 +96,7 @@ async def throttled_gather(
|
|
|
96
96
|
) -> list[_T2]: ...
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
async def
|
|
99
|
+
async def async_map(
|
|
100
100
|
coro_factory: Callable[[_T1], Awaitable[_T2]],
|
|
101
101
|
values: Iterable[_T1],
|
|
102
102
|
*,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|