python-dropbox-api 0.1.3__tar.gz → 0.1.5__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.
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/PKG-INFO +2 -1
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/pyproject.toml +1 -1
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/python_dropbox_api/client.py +48 -10
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/LICENSE +0 -0
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/README.md +0 -0
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/python_dropbox_api/__init__.py +0 -0
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/python_dropbox_api/auth.py +0 -0
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/python_dropbox_api/exceptions.py +0 -0
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/python_dropbox_api/models.py +0 -0
- {python_dropbox_api-0.1.3 → python_dropbox_api-0.1.5}/python_dropbox_api/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-dropbox-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: This is a lightweight wrapper for the Dropbox API intended for use in Home Assistant.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -10,6 +10,7 @@ Requires-Python: >=3.13
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
13
14
|
Requires-Dist: aiohttp (>=3.13.0,<4.0.0)
|
|
14
15
|
Description-Content-Type: text/markdown
|
|
15
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-dropbox-api"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.5"
|
|
4
4
|
description = "This is a lightweight wrapper for the Dropbox API intended for use in Home Assistant."
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Brandon Rothweiler",email = "2292715+bdr99@users.noreply.github.com"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from collections.abc import AsyncIterator
|
|
1
|
+
from collections.abc import AsyncIterator, Callable
|
|
2
2
|
import json
|
|
3
3
|
|
|
4
4
|
from aiohttp import ClientResponse
|
|
@@ -38,15 +38,24 @@ def parse_property_groups(property_groups: list[dict]) -> list[PropertyGroup]:
|
|
|
38
38
|
|
|
39
39
|
async def handle_common_errors(response: ClientResponse) -> None:
|
|
40
40
|
"""Handle common errors."""
|
|
41
|
-
|
|
41
|
+
if response.ok:
|
|
42
|
+
return
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
try:
|
|
45
|
+
response_json = await response.json(content_type=None)
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
error_summary = response_json.get("error_summary") if isinstance(response_json, dict) else None
|
|
48
|
+
|
|
49
|
+
if error_summary is not None:
|
|
50
|
+
if error_summary.startswith("invalid_access_token/"):
|
|
51
|
+
raise DropboxAuthException("Unauthorized")
|
|
52
|
+
if error_summary.startswith("path/not_found/"):
|
|
53
|
+
raise DropboxFileOrFolderNotFoundException("File or folder not found")
|
|
54
|
+
except (DropboxAuthException, DropboxFileOrFolderNotFoundException):
|
|
55
|
+
raise
|
|
56
|
+
except json.JSONDecodeError:
|
|
57
|
+
text = await response.text()
|
|
58
|
+
raise DropboxUnknownException(f"{response.status}: {text}")
|
|
50
59
|
|
|
51
60
|
response.raise_for_status()
|
|
52
61
|
|
|
@@ -229,6 +238,7 @@ class DropboxAPIClient:
|
|
|
229
238
|
path: str,
|
|
230
239
|
file_stream: AsyncIterator[bytes],
|
|
231
240
|
property_groups: list[PropertyGroup] | None = None,
|
|
241
|
+
progress_callback: Callable[[int], None] | None = None,
|
|
232
242
|
) -> None:
|
|
233
243
|
"""Upload a file to Dropbox using chunked upload sessions.
|
|
234
244
|
|
|
@@ -236,13 +246,19 @@ class DropboxAPIClient:
|
|
|
236
246
|
path: The Dropbox path where the file should be uploaded.
|
|
237
247
|
file_stream: An async iterator of bytes to upload.
|
|
238
248
|
property_groups: Optional list of property groups to attach to the uploaded file.
|
|
249
|
+
progress_callback: Optional callback called with the total number of bytes uploaded after each chunk is sent.
|
|
239
250
|
"""
|
|
240
251
|
try:
|
|
241
252
|
CHUNK_SIZE = 16 * 1024 * 1024 # 16MB chunks
|
|
242
253
|
|
|
243
254
|
# Always use chunked upload approach
|
|
244
255
|
await self._upload_file_chunked(
|
|
245
|
-
CONTENT_API_BASE_URL,
|
|
256
|
+
CONTENT_API_BASE_URL,
|
|
257
|
+
path,
|
|
258
|
+
file_stream,
|
|
259
|
+
CHUNK_SIZE,
|
|
260
|
+
property_groups,
|
|
261
|
+
progress_callback,
|
|
246
262
|
)
|
|
247
263
|
except (DropboxAuthException, DropboxFileOrFolderNotFoundException):
|
|
248
264
|
raise
|
|
@@ -256,6 +272,7 @@ class DropboxAPIClient:
|
|
|
256
272
|
file_stream: AsyncIterator[bytes],
|
|
257
273
|
chunk_size: int,
|
|
258
274
|
property_groups: list[PropertyGroup] | None = None,
|
|
275
|
+
progress_callback: Callable[[int], None] | None = None,
|
|
259
276
|
) -> None:
|
|
260
277
|
"""Upload a file using chunked upload sessions, streaming chunks without loading entire file into memory."""
|
|
261
278
|
session_id = None
|
|
@@ -286,6 +303,8 @@ class DropboxAPIClient:
|
|
|
286
303
|
)
|
|
287
304
|
|
|
288
305
|
offset += len(chunk_data)
|
|
306
|
+
if progress_callback:
|
|
307
|
+
progress_callback(offset)
|
|
289
308
|
|
|
290
309
|
# Handle remaining data in buffer (final partial chunk)
|
|
291
310
|
if buffer:
|
|
@@ -298,6 +317,13 @@ class DropboxAPIClient:
|
|
|
298
317
|
content_api_url, session_id, offset, buffer
|
|
299
318
|
)
|
|
300
319
|
offset += len(buffer)
|
|
320
|
+
if progress_callback:
|
|
321
|
+
progress_callback(offset)
|
|
322
|
+
|
|
323
|
+
# Empty file (or a stream that yielded no bytes): no session was ever
|
|
324
|
+
# started, so open one with no data before finishing.
|
|
325
|
+
if session_id is None:
|
|
326
|
+
session_id = await self._start_upload_session(content_api_url, b"")
|
|
301
327
|
|
|
302
328
|
# Finish upload session
|
|
303
329
|
await self._finish_upload_session(
|
|
@@ -429,7 +455,7 @@ class DropboxAPIClient:
|
|
|
429
455
|
chunk_size = 1024 * 1024 # 1MB
|
|
430
456
|
|
|
431
457
|
async with self._websession.post(url, headers=headers) as response:
|
|
432
|
-
response
|
|
458
|
+
await handle_common_errors(response)
|
|
433
459
|
async for chunk in response.content.iter_chunked(chunk_size):
|
|
434
460
|
if chunk:
|
|
435
461
|
yield chunk
|
|
@@ -465,6 +491,18 @@ class DropboxAPIClient:
|
|
|
465
491
|
url, headers=headers, json=payload
|
|
466
492
|
) as response:
|
|
467
493
|
await handle_common_errors(response)
|
|
494
|
+
|
|
495
|
+
response_json = await response.json()
|
|
496
|
+
|
|
497
|
+
# create_folder_v2 wraps the folder metadata under "metadata".
|
|
498
|
+
metadata = response_json["metadata"]
|
|
499
|
+
|
|
500
|
+
return FileOrFolderInfo(
|
|
501
|
+
is_folder=True,
|
|
502
|
+
name=metadata["name"],
|
|
503
|
+
size=None,
|
|
504
|
+
property_groups=None,
|
|
505
|
+
)
|
|
468
506
|
except (DropboxAuthException, DropboxFileOrFolderNotFoundException):
|
|
469
507
|
raise
|
|
470
508
|
except Exception as err:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|