Skip to content

Commit ed6aeda

Browse files
block/upload: add download_file() (backport of jamalex#209)
1 parent f202592 commit ed6aeda

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

notion/block/upload.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import os
22
from mimetypes import guess_type
3-
from urllib.parse import urlencode, urlparse
3+
from urllib.parse import urlencode, urlparse, quote
44

55
from notion.block.embed import EmbedBlock
66
from notion.maps import field_map, property_map
7-
from notion.utils import human_size
7+
from notion.settings import SIGNED_URL_PREFIX
8+
from notion.utils import human_size, from_list
89

910

1011
class UploadBlock(EmbedBlock):
@@ -61,6 +62,45 @@ def upload_file(self, path: str):
6162
self.display_source = query_url
6263
self.file_id = urlparse(url).path.split("/")[2]
6364

65+
def download_file(self, path: str):
66+
"""
67+
Download a file.
68+
69+
70+
Arguments
71+
---------
72+
path : str
73+
Path for saving file.
74+
75+
76+
Raises
77+
------
78+
HTTPError
79+
On API error.
80+
"""
81+
82+
record_data = self._get_record_data()
83+
source = record_data["properties"]["source"]
84+
s3_url = from_list(source)
85+
file_name = s3_url.split("/")[-1]
86+
87+
params = {
88+
"cache": "v2",
89+
"name": file_name,
90+
"id": self._id,
91+
"table": self._table,
92+
"userId": self._client.current_user.id,
93+
"download": True,
94+
}
95+
96+
url = SIGNED_URL_PREFIX + quote(s3_url, safe="")
97+
resp = self._client.session.get(url, params=params, stream=True)
98+
resp.raise_for_status()
99+
100+
with open(path, "wb") as f:
101+
for chunk in resp.iter_content(chunk_size=4096):
102+
f.write(chunk)
103+
64104

65105
class FileBlock(UploadBlock):
66106
"""

notion/utils.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,28 @@ def to_list(value) -> list:
3333
return value if isinstance(value, list) else [value]
3434

3535

36+
def from_list(value) -> Any:
37+
"""
38+
Unwrap value from nested list.
39+
40+
41+
Arguments
42+
---------
43+
value : List
44+
Nested list with target value.
45+
46+
47+
Returns
48+
-------
49+
Any
50+
Value from nested list.
51+
"""
52+
if "__iter__" in dir(value) and not isinstance(value, str):
53+
return from_list(next(iter(value), None))
54+
55+
return value
56+
57+
3658
def now() -> int:
3759
"""
3860
Get UNIX-style time since epoch in seconds.

smoke_tests/block/test_upload.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
from notion.block.upload import PdfBlock, ImageBlock, VideoBlock, FileBlock
24
from smoke_tests.conftest import assert_block_is_okay, assert_block_attributes
35

@@ -19,19 +21,30 @@ def test_file_block(notion):
1921
assert "secure.notion-static.com" in block.source
2022
assert len(block.file_id) == 36
2123

24+
title_bak = f"{title}.bak"
25+
block.download_file(title_bak)
26+
27+
assert os.path.isfile(title_bak)
28+
29+
os.remove(title_bak)
30+
2231

2332
def test_image_block(notion):
2433
block = notion.root_page.children.add_new(ImageBlock)
2534
assert_block_is_okay(**locals(), type="image")
35+
2636
source = "https://raw.githubusercontent.com/jamalex/"
2737
source = source + "notion-py/master/ezgif-3-a935fdcb7415.gif"
38+
2839
assert_block_attributes(block, source=source, caption="caption")
2940

3041

3142
def test_video_block(notion):
3243
block = notion.root_page.children.add_new(VideoBlock)
3344
assert_block_is_okay(**locals(), type="video")
45+
3446
source = "https://streamable.com/8ud2kh"
47+
3548
assert_block_attributes(block, source=source, caption="caption")
3649

3750

0 commit comments

Comments
 (0)