async-mega-py 2.2.0__tar.gz → 2.2.2__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.
Files changed (25) hide show
  1. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/PKG-INFO +25 -26
  2. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/README.md +24 -25
  3. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/pyproject.toml +1 -1
  4. async_mega_py-2.2.2/src/mega/__init__.py +8 -0
  5. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/__main__.py +1 -2
  6. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/api.py +30 -44
  7. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/client.py +6 -3
  8. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/data_structures.py +4 -2
  9. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/transfer_it.py +7 -3
  10. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/utils.py +2 -1
  11. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/vault.py +4 -2
  12. async_mega_py-2.2.0/src/mega/__init__.py +0 -4
  13. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/LICENSE +0 -0
  14. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/auth.py +0 -0
  15. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/chunker.py +0 -0
  16. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/core.py +0 -0
  17. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/crypto.py +0 -0
  18. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/download.py +0 -0
  19. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/env.py +0 -0
  20. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/errors.py +0 -0
  21. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/filesystem.py +0 -0
  22. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/progress/__init__.py +0 -0
  23. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/progress/rich_progress.py +0 -0
  24. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/py.typed +0 -0
  25. {async_mega_py-2.2.0 → async_mega_py-2.2.2}/src/mega/upload.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: async-mega.py
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: Python library for the Mega.nz and Transfer.it API
5
5
  Keywords: api,downloader,mega,mega.nz,transfer.it
6
6
  Author: NTFSvolume
@@ -79,7 +79,7 @@ Please check [`src/mega/data_structures.py`](src/mega/data_structures.py) for de
79
79
  > [!TIP]
80
80
  > You can run the commands bellow in an interactive python (the asyncio REPL). Try them in real time as is, using `async/await` keywords!
81
81
  >
82
- > ```uv run -p3.12 --with async-mega-py python -m asyncio```
82
+ > `uv run -p3.12 --with async-mega-py python -m asyncio`
83
83
 
84
84
  ```python
85
85
  from mega.client import MegaNzClient
@@ -99,7 +99,7 @@ from mega.client import MegaNzClient
99
99
  # Also works without using it as a context manager, but you have the responsability to close the session at the end
100
100
  mega = MegaNzClient()
101
101
  await mega.login() # login using a temporary anonymous account
102
- # await mega.close()
102
+ # await mega.close()
103
103
 
104
104
  ```
105
105
 
@@ -163,7 +163,7 @@ await mega.download(uploaded_file, output_dir)
163
163
 
164
164
  # Download a public file
165
165
  file_url = "https://mega.nz/file/vJ9EBJBC#vA1XpbngXcnN7lqXEWGQFPDc5ZlG6yltCHwGN-0O2LQ"
166
- public_handle, public_key = mega.parse_file_url(file_url)
166
+ public_handle, public_key = mega.parse_file_url(file_url)
167
167
  await mega.download_public_file(public_handle, public_key, output_dir)
168
168
 
169
169
  # Download a public folder
@@ -186,7 +186,7 @@ print (result.is_folder)
186
186
  > You can show a progress bar on the terminal for each download/upload by calling them within the `progress_bar` context manager (needs optional dependency `rich` to be installed):
187
187
 
188
188
  ```python
189
- with mega.progress_bar:
189
+ with mega.progress_bar:
190
190
  results = await mega.download_public_folder(public_handle, public_key, output_dir / "with_bar")
191
191
  ```
192
192
 
@@ -264,16 +264,14 @@ The output will be:
264
264
 
265
265
  ```json
266
266
  {
267
- "oImwb6nN": "/tests/script.js",
268
- "FIXitv4F": "/tests/scripts",
269
- "0fPFklV3": "/tests/scripts/notes.txt",
270
- "l9zkz1GU": "/tests/scripts/script.js",
271
- "E4LqT4EF": "/tests/scripts/styles.css",
267
+ "oImwb6nN": "/tests/script.js",
268
+ "FIXitv4F": "/tests/scripts",
269
+ "0fPFklV3": "/tests/scripts/notes.txt",
270
+ "l9zkz1GU": "/tests/scripts/script.js",
271
+ "E4LqT4EF": "/tests/scripts/styles.css"
272
272
  }
273
273
  ```
274
274
 
275
-
276
-
277
275
  ```python
278
276
  # Get the path to a node
279
277
  fs.absolute_path("0fPFklV3") # /tests/scripts/notes.txt
@@ -294,24 +292,25 @@ for node in fs.iterdir(folder.id, recursive=True):
294
292
  print(fs.absolute_path(node.id))
295
293
 
296
294
  ```
295
+
297
296
  Output will be:
298
297
 
299
298
  ```json
300
299
  [
301
- "/tests/logo.png",
302
- "/tests/logo.png",
303
- "/tests/script.js",
304
- "/tests/scripts",
305
- "/tests/scripts/notes.txt",
306
- "/tests/scripts/script.js",
307
- "/tests/scripts/styles.css",
308
- "/tests/setup.sh",
309
- "/tests/utils.py",
300
+ "/tests/logo.png",
301
+ "/tests/logo.png",
302
+ "/tests/script.js",
303
+ "/tests/scripts",
304
+ "/tests/scripts/notes.txt",
305
+ "/tests/scripts/script.js",
306
+ "/tests/scripts/styles.css",
307
+ "/tests/setup.sh",
308
+ "/tests/utils.py"
310
309
  ]
311
310
  ```
312
311
 
313
312
  > [!IMPORTANT]
314
- > Mega's filesystem is *not* POSIX-compliant: multiple nodes may have the same path.
313
+ > Mega's filesystem is _not_ POSIX-compliant: multiple nodes may have the same path.
315
314
  >
316
315
  > If 2 nodes have the same path, `find` will throw an error.
317
316
 
@@ -352,10 +351,10 @@ mega-py --help
352
351
  ```
353
352
 
354
353
  ```powershell
355
- Usage: mega-py [OPTIONS] COMMAND [ARGS]...
354
+ Usage: mega-py [OPTIONS] COMMAND [ARGS]...
356
355
 
357
- CLI app for the Mega.nz and Transfer.it. Set MEGA_NZ_EMAIL and MEGA_NZ_PASSWORD
358
- enviroment variables to use them as credentials for Mega
356
+ CLI app for the Mega.nz and Transfer.it. Set MEGA_EMAIL and MEGA_PWD
357
+ enviroment variables to use them as credentials for Mega
359
358
 
360
359
  ╭─ Options ──────────────────────────────────────────────────────────────────────╮
361
360
  │ --verbose -v Increase verbosity (-v shows debug logs, -vv │
@@ -371,6 +370,6 @@ Usage: mega-py [OPTIONS] COMMAND [ARGS]...
371
370
  ```
372
371
 
373
372
  > [!TIP]
374
- > The CLI app does *not* accept login credentials, but you can still use your account by setting up the `MEGA_EMAIL` and `MEGA_PWD` enviroment variables
373
+ > The CLI app does _not_ accept login credentials, but you can still use your account by setting up the `MEGA_EMAIL` and `MEGA_PWD` enviroment variables
375
374
  >
376
375
  > It will also read them from an `.env` file (if found)
@@ -46,7 +46,7 @@ Please check [`src/mega/data_structures.py`](src/mega/data_structures.py) for de
46
46
  > [!TIP]
47
47
  > You can run the commands bellow in an interactive python (the asyncio REPL). Try them in real time as is, using `async/await` keywords!
48
48
  >
49
- > ```uv run -p3.12 --with async-mega-py python -m asyncio```
49
+ > `uv run -p3.12 --with async-mega-py python -m asyncio`
50
50
 
51
51
  ```python
52
52
  from mega.client import MegaNzClient
@@ -66,7 +66,7 @@ from mega.client import MegaNzClient
66
66
  # Also works without using it as a context manager, but you have the responsability to close the session at the end
67
67
  mega = MegaNzClient()
68
68
  await mega.login() # login using a temporary anonymous account
69
- # await mega.close()
69
+ # await mega.close()
70
70
 
71
71
  ```
72
72
 
@@ -130,7 +130,7 @@ await mega.download(uploaded_file, output_dir)
130
130
 
131
131
  # Download a public file
132
132
  file_url = "https://mega.nz/file/vJ9EBJBC#vA1XpbngXcnN7lqXEWGQFPDc5ZlG6yltCHwGN-0O2LQ"
133
- public_handle, public_key = mega.parse_file_url(file_url)
133
+ public_handle, public_key = mega.parse_file_url(file_url)
134
134
  await mega.download_public_file(public_handle, public_key, output_dir)
135
135
 
136
136
  # Download a public folder
@@ -153,7 +153,7 @@ print (result.is_folder)
153
153
  > You can show a progress bar on the terminal for each download/upload by calling them within the `progress_bar` context manager (needs optional dependency `rich` to be installed):
154
154
 
155
155
  ```python
156
- with mega.progress_bar:
156
+ with mega.progress_bar:
157
157
  results = await mega.download_public_folder(public_handle, public_key, output_dir / "with_bar")
158
158
  ```
159
159
 
@@ -231,16 +231,14 @@ The output will be:
231
231
 
232
232
  ```json
233
233
  {
234
- "oImwb6nN": "/tests/script.js",
235
- "FIXitv4F": "/tests/scripts",
236
- "0fPFklV3": "/tests/scripts/notes.txt",
237
- "l9zkz1GU": "/tests/scripts/script.js",
238
- "E4LqT4EF": "/tests/scripts/styles.css",
234
+ "oImwb6nN": "/tests/script.js",
235
+ "FIXitv4F": "/tests/scripts",
236
+ "0fPFklV3": "/tests/scripts/notes.txt",
237
+ "l9zkz1GU": "/tests/scripts/script.js",
238
+ "E4LqT4EF": "/tests/scripts/styles.css"
239
239
  }
240
240
  ```
241
241
 
242
-
243
-
244
242
  ```python
245
243
  # Get the path to a node
246
244
  fs.absolute_path("0fPFklV3") # /tests/scripts/notes.txt
@@ -261,24 +259,25 @@ for node in fs.iterdir(folder.id, recursive=True):
261
259
  print(fs.absolute_path(node.id))
262
260
 
263
261
  ```
262
+
264
263
  Output will be:
265
264
 
266
265
  ```json
267
266
  [
268
- "/tests/logo.png",
269
- "/tests/logo.png",
270
- "/tests/script.js",
271
- "/tests/scripts",
272
- "/tests/scripts/notes.txt",
273
- "/tests/scripts/script.js",
274
- "/tests/scripts/styles.css",
275
- "/tests/setup.sh",
276
- "/tests/utils.py",
267
+ "/tests/logo.png",
268
+ "/tests/logo.png",
269
+ "/tests/script.js",
270
+ "/tests/scripts",
271
+ "/tests/scripts/notes.txt",
272
+ "/tests/scripts/script.js",
273
+ "/tests/scripts/styles.css",
274
+ "/tests/setup.sh",
275
+ "/tests/utils.py"
277
276
  ]
278
277
  ```
279
278
 
280
279
  > [!IMPORTANT]
281
- > Mega's filesystem is *not* POSIX-compliant: multiple nodes may have the same path.
280
+ > Mega's filesystem is _not_ POSIX-compliant: multiple nodes may have the same path.
282
281
  >
283
282
  > If 2 nodes have the same path, `find` will throw an error.
284
283
 
@@ -319,10 +318,10 @@ mega-py --help
319
318
  ```
320
319
 
321
320
  ```powershell
322
- Usage: mega-py [OPTIONS] COMMAND [ARGS]...
321
+ Usage: mega-py [OPTIONS] COMMAND [ARGS]...
323
322
 
324
- CLI app for the Mega.nz and Transfer.it. Set MEGA_NZ_EMAIL and MEGA_NZ_PASSWORD
325
- enviroment variables to use them as credentials for Mega
323
+ CLI app for the Mega.nz and Transfer.it. Set MEGA_EMAIL and MEGA_PWD
324
+ enviroment variables to use them as credentials for Mega
326
325
 
327
326
  ╭─ Options ──────────────────────────────────────────────────────────────────────╮
328
327
  │ --verbose -v Increase verbosity (-v shows debug logs, -vv │
@@ -338,6 +337,6 @@ Usage: mega-py [OPTIONS] COMMAND [ARGS]...
338
337
  ```
339
338
 
340
339
  > [!TIP]
341
- > The CLI app does *not* accept login credentials, but you can still use your account by setting up the `MEGA_EMAIL` and `MEGA_PWD` enviroment variables
340
+ > The CLI app does _not_ accept login credentials, but you can still use your account by setting up the `MEGA_EMAIL` and `MEGA_PWD` enviroment variables
342
341
  >
343
342
  > It will also read them from an `.env` file (if found)
@@ -34,7 +34,7 @@ license = "Apache-2.0"
34
34
  license-files = ["LICENSE"]
35
35
  readme = "README.md"
36
36
  requires-python = ">=3.11"
37
- version = "2.2.0"
37
+ version = "2.2.2"
38
38
 
39
39
  [project.optional-dependencies]
40
40
  cli = [
@@ -0,0 +1,8 @@
1
+ import importlib.metadata
2
+ from contextvars import ContextVar
3
+
4
+ _package_name_ = "async-mega-py"
5
+ __version__ = importlib.metadata.version(_package_name_)
6
+
7
+ LOG_FILE_PROGRESS: ContextVar[bool] = ContextVar("LOG_FILE_PROGRESS", default=True)
8
+ LOG_HTTP_TRAFFIC: ContextVar[bool] = ContextVar("LOG_HTTP_TRAFFIC", default=False)
@@ -14,8 +14,7 @@ _ = install_rich_traceback(width=None, max_frames=2)
14
14
  import yarl
15
15
  from cyclopts import App, Parameter
16
16
 
17
- from mega import __version__, env
18
- from mega.api import LOG_HTTP_TRAFFIC
17
+ from mega import LOG_HTTP_TRAFFIC, __version__, env
19
18
  from mega.client import MegaNzClient
20
19
  from mega.transfer_it import TransferItClient
21
20
  from mega.utils import Site, setup_logger
@@ -7,15 +7,14 @@ import json
7
7
  import logging
8
8
  import uuid
9
9
  from collections.abc import Mapping, Sequence
10
- from contextvars import ContextVar
11
10
  from functools import wraps
12
- from typing import TYPE_CHECKING, Any, ClassVar, Literal, ParamSpec, Self, TypeVar
11
+ from typing import TYPE_CHECKING, Any, ClassVar, Generic, Literal, ParamSpec, Self, TypeVar
13
12
 
14
13
  import aiohttp
15
14
  import yarl
16
15
  from aiolimiter import AsyncLimiter
17
16
 
18
- from mega import __version__, _package_name_
17
+ from mega import LOG_HTTP_TRAFFIC, __version__, _package_name_
19
18
  from mega.crypto import generate_hashcash
20
19
  from mega.errors import RequestError, RetryRequestError
21
20
  from mega.utils import random_id, random_u32int
@@ -27,8 +26,6 @@ if TYPE_CHECKING:
27
26
  _R = TypeVar("_R")
28
27
 
29
28
 
30
- LOG_HTTP_TRAFFIC: ContextVar[bool] = ContextVar("LOG_HTTP_TRAFFIC", default=False)
31
-
32
29
  logger = logging.getLogger(__name__)
33
30
 
34
31
 
@@ -66,27 +63,23 @@ def retry(
66
63
  return wrapper
67
64
 
68
65
 
69
- @dataclasses.dataclass(slots=True, weakref_slot=True, init=False)
66
+ @dataclasses.dataclass(slots=True, weakref_slot=True)
70
67
  class MegaAPI:
71
- session_id: str | None
72
- _request_id: int
73
- _client_id: str
74
-
75
- __session: aiohttp.ClientSession | None
76
- _auto_close_session: bool
77
- _rate_limiter: AsyncLimiter
78
-
79
- _entrypoint: ClassVar[yarl.URL] = yarl.URL("https://g.api.mega.co.nz/cs")
80
- user_agent: str
81
-
82
- def __init__(self, session: aiohttp.ClientSession | None = None, user_agent: str | None = None) -> None:
83
- self.session_id = None
84
- self._request_id = random_u32int()
85
- self._client_id = random_id(10)
86
- self.__session = session
87
- self._auto_close_session = session is None
88
- self._rate_limiter = AsyncLimiter(100, 60)
89
- self.user_agent = user_agent or f"{_package_name_}/{__version__}"
68
+ _session: aiohttp.ClientSession | None = None
69
+
70
+ user_agent: str = f"{_package_name_}/{__version__}"
71
+
72
+ session_id: str | None = dataclasses.field(init=False, default=None)
73
+ _request_id: int = dataclasses.field(init=False, default_factory=random_u32int)
74
+ _client_id: str = dataclasses.field(init=False, default_factory=lambda: random_id(10))
75
+
76
+ _auto_close_session: bool = dataclasses.field(init=False)
77
+ _rate_limiter: AsyncLimiter = dataclasses.field(init=False, default_factory=lambda: AsyncLimiter(100, 60))
78
+
79
+ _entrypoint: ClassVar[yarl.URL] = dataclasses.field(init=False, default=yarl.URL("https://g.api.mega.co.nz/cs"))
80
+
81
+ def __post_init__(self) -> None:
82
+ self._auto_close_session = self._session is None
90
83
 
91
84
  @property
92
85
  def entrypoint(self) -> yarl.URL:
@@ -96,22 +89,12 @@ class MegaAPI:
96
89
  def client_id(self) -> str:
97
90
  return self._client_id
98
91
 
99
- @property
100
- def request_id(self) -> int:
101
- return self._request_id
102
-
103
- @property
104
- def _session(self) -> aiohttp.ClientSession:
105
- if self.__session is None:
106
- self.__session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(sock_connect=160, sock_read=60))
107
- return self.__session
108
-
109
92
  def __repr__(self) -> str:
110
93
  return f"<{type(self).__name__}>(session_id={self.session_id!r}, client_id={self.client_id!r}, auto_close_session={self._auto_close_session!r})"
111
94
 
112
95
  async def aclose(self) -> None:
113
- if self._auto_close_session and self.__session:
114
- await self.__session.close()
96
+ if self._auto_close_session and self._session:
97
+ await self._session.close()
115
98
 
116
99
  async def __enter__(self) -> Self:
117
100
  return self
@@ -175,7 +158,7 @@ class MegaAPI:
175
158
  headers: Mapping[str, str] | None = None,
176
159
  **kwargs: Any,
177
160
  ) -> AsyncGenerator[aiohttp.ClientResponse]:
178
- kwargs["headers"] = {"User-Agent": self.user_agent} | (headers or {})
161
+ kwargs["headers"] = {"User-Agent": self.user_agent, **(headers or {})}
179
162
  request_id = str(uuid.uuid4())
180
163
  if LOG_HTTP_TRAFFIC.get():
181
164
  logger.debug(
@@ -187,6 +170,9 @@ class MegaAPI:
187
170
  )
188
171
 
189
172
  resp = None
173
+ if self._session is None:
174
+ self._session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(sock_connect=160, sock_read=60))
175
+
190
176
  try:
191
177
  async with self._rate_limiter, self._session.request(method, url, **kwargs) as resp:
192
178
  yield resp
@@ -244,19 +230,19 @@ class _LazyResponseLog:
244
230
  return str(self.__json__())
245
231
 
246
232
 
247
- class APIContextManager:
248
- __slots__ = ("_api",)
233
+ _API_T = TypeVar("_API_T", bound=MegaAPI, covariant=True)
249
234
 
250
- def __init__(self, session: aiohttp.ClientSession | None = None, *, user_agent: str | None = None) -> None:
251
- self._api: MegaAPI = MegaAPI(session, user_agent)
235
+
236
+ class APIContextManager(Generic[_API_T]):
237
+ __slots__ = ("_api",)
252
238
 
253
239
  async def __aenter__(self) -> Self:
254
240
  return self
255
241
 
256
242
  async def __aexit__(self, *_) -> None:
257
- await self.close()
243
+ await self.aclose()
258
244
 
259
245
  async def aclose(self) -> None:
260
- await self._api.close()
246
+ await self._api.aclose()
261
247
 
262
248
  close = aclose
@@ -7,7 +7,7 @@ from pathlib import Path, PurePosixPath
7
7
  from typing import TYPE_CHECKING
8
8
 
9
9
  from mega import progress
10
- from mega.api import APIContextManager
10
+ from mega.api import APIContextManager, MegaAPI
11
11
  from mega.core import MegaCore
12
12
  from mega.crypto import a32_to_base64, b64_to_a32, b64_url_encode, encrypt_attr, encrypt_key
13
13
  from mega.data_structures import (
@@ -38,13 +38,16 @@ logger = logging.getLogger(__name__)
38
38
  _DOMAIN = Site.MEGA.value
39
39
 
40
40
 
41
- class MegaNzClient(APIContextManager):
41
+ class MegaNzClient(APIContextManager[MegaAPI]):
42
42
  """Interface with all the public methods of the API"""
43
43
 
44
44
  __slots__ = ("_core",)
45
45
 
46
46
  def __init__(self, session: aiohttp.ClientSession | None = None, *, user_agent: str | None = None) -> None:
47
- super().__init__(session, user_agent=user_agent)
47
+ self._api = MegaAPI(session)
48
+ if user_agent:
49
+ self._api.user_agent = user_agent
50
+
48
51
  self._core: MegaCore = MegaCore(self._api)
49
52
  if hasattr(sys, "ps1"):
50
53
  setup_logger(logging.DEBUG)
@@ -13,7 +13,7 @@ import dataclasses
13
13
  import time
14
14
  from enum import IntEnum
15
15
  from types import MappingProxyType
16
- from typing import TYPE_CHECKING, Any, ClassVar, Final, Self, TypeAlias, TypedDict
16
+ from typing import TYPE_CHECKING, Any, ClassVar, Final, Literal, Self, TypeAlias, TypedDict
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from collections.abc import Mapping
@@ -67,7 +67,7 @@ class NodeSerialized(TypedDict):
67
67
  h: NodeID # ID
68
68
  p: NodeID # Parent ID
69
69
  u: NotRequired[UserID] # Owner (user ID), not present in transfer.it nodes
70
- t: ReadOnly[NodeType]
70
+ t: ReadOnly[Literal[0, 1, 2, 3, 4, 5]] # Node type
71
71
  a: str # Serialized attributes
72
72
  ts: TimeStamp # creation date
73
73
 
@@ -76,6 +76,7 @@ class NodeSerialized(TypedDict):
76
76
  sk: NotRequired[str] # Share key, only present present in shared (public) files / folder
77
77
 
78
78
  s: NotRequired[int] # size (files only)
79
+ fa: NotRequired[str] # additional file attributes for multimedia files (ex: thumbail)
79
80
 
80
81
 
81
82
  class OwnerKeys(TypedDict):
@@ -267,6 +268,7 @@ class Node(_DictDumper):
267
268
  keys: dict[str, str] = {}
268
269
 
269
270
  size = node.get("s")
271
+
270
272
  return Node(
271
273
  id=node["h"],
272
274
  parent_id=node["p"],
@@ -45,9 +45,13 @@ class TransferItAPI(MegaAPI):
45
45
  return await super().post(json, params)
46
46
 
47
47
 
48
- class TransferItClient(APIContextManager):
49
- def __init__(self, session: aiohttp.ClientSession | None = None, *, user_agent: str | None = None) -> None: # pyright: ignore[reportMissingSuperCall]
50
- self._api = TransferItAPI(session, user_agent=user_agent)
48
+ class TransferItClient(APIContextManager[TransferItAPI]):
49
+ __slots__ = ()
50
+
51
+ def __init__(self, session: aiohttp.ClientSession | None = None, *, user_agent: str | None = None) -> None:
52
+ self._api = TransferItAPI(session)
53
+ if user_agent:
54
+ self._api.user_agent = user_agent
51
55
 
52
56
  @property
53
57
  def progress_bar(self) -> _GeneratorContextManager[None, None, None]:
@@ -14,6 +14,7 @@ from typing import TYPE_CHECKING, Literal, TypeVar, overload
14
14
  import aiohttp
15
15
  import yarl
16
16
 
17
+ from mega import LOG_FILE_PROGRESS
17
18
  from mega.errors import ValidationError
18
19
 
19
20
  if TYPE_CHECKING:
@@ -63,7 +64,7 @@ def setup_logger(level: int = logging.INFO) -> None:
63
64
 
64
65
 
65
66
  def progress_logger(output_path: Path, file_size: int, *, download: bool) -> Callable[[float], None]:
66
- if not logger.isEnabledFor(10):
67
+ if not (LOG_FILE_PROGRESS.get() and logger.isEnabledFor(logging.DEBUG)):
67
68
  return lambda _: None
68
69
 
69
70
  from mega.data_structures import ByteSize
@@ -50,12 +50,14 @@ class MegaVault:
50
50
 
51
51
  # files shared with me
52
52
  elif node.owner in self._shared_keys:
53
- real_node_id, share_key = next(p for p in self._shared_keys[node.owner].items() if p[0] in node.keys)
53
+ real_node_id = next(node_id for node_id in node.keys if node_id in self._shared_keys[node.owner])
54
+ share_key = self._shared_keys[node.owner][real_node_id]
54
55
  full_key = decrypt_key(b64_to_a32(node.keys[real_node_id]), share_key)
55
56
 
56
57
  # public files/folders
57
58
  elif share_key := self._shared_keys[_EXPORTED].get(node.id):
58
- encrypted_key = b64_to_a32(next(iter(node.keys.values())))
59
+ real_node_id = next(node_id for node_id in node.keys if node_id in self._shared_keys[_EXPORTED])
60
+ encrypted_key = b64_to_a32(node.keys[real_node_id])
59
61
  full_key = decrypt_key(encrypted_key, share_key)
60
62
 
61
63
  else:
@@ -1,4 +0,0 @@
1
- import importlib.metadata
2
-
3
- _package_name_ = "async-mega-py"
4
- __version__ = importlib.metadata.version(_package_name_)
File without changes