Skip to content

Commit c90d796

Browse files
committed
Add retry mechanism and error handling
1 parent a2d957d commit c90d796

File tree

2 files changed

+65
-26
lines changed

2 files changed

+65
-26
lines changed

gkeep2notion.py

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/local/bin/python3
2+
from typing import List, Dict
23
from argparse import ArgumentParser
34
from configparser import ConfigParser
45
from enum import Enum
@@ -9,7 +10,7 @@
910
import urllib.request
1011

1112
from gkeepapi import Keep, node
12-
from notion_client import Client
13+
from notion_client import Client, errors
1314
import time
1415

1516

@@ -67,7 +68,7 @@ def _parse(self, text: str):
6768
self.add_chunk(c)
6869

6970
@property
70-
def chunks(self) -> list[dict]:
71+
def chunks(self) -> List[Dict]:
7172
return self._chunks
7273

7374
def add_chunk(self, text: str, url: str = ''):
@@ -101,7 +102,7 @@ def __init__(self, title: str, parent_id: str):
101102
self._parent_id = parent_id
102103
self._children = []
103104

104-
def render(self) -> dict:
105+
def render(self) -> Dict:
105106
return {
106107
"properties": {
107108
"title": [{"text": {"content": self._title}}]
@@ -114,20 +115,20 @@ def render(self) -> dict:
114115
}
115116

116117
@property
117-
def parent(self) -> dict:
118+
def parent(self) -> Dict:
118119
return {
119120
"type": "page_id",
120121
"page_id": self._parent_id
121122
}
122123

123124
@property
124-
def properties(self) -> dict:
125+
def properties(self) -> Dict:
125126
return {
126127
"title": [{"text": {"content": self._title}}]
127128
}
128129

129130
@property
130-
def children(self) -> dict:
131+
def children(self) -> Dict:
131132
return self._children
132133

133134
@property
@@ -254,7 +255,7 @@ def downloadFile(url, path):
254255
urllib.request.urlretrieve(url, path)
255256

256257

257-
def parseBlock(p: str) -> dict:
258+
def parseBlock(p: str) -> Dict:
258259
"""Parses a line from a Keep Note into a Notion block type and text
259260
260261
Supported block types:
@@ -296,14 +297,14 @@ def parseTextToPage(text: str, page: Page):
296297
page.add_text(block['text'], block['type'])
297298

298299

299-
def getNoteCategories(note: node.TopLevelNode) -> list[str]:
300+
def getNoteCategories(note: node.TopLevelNode) -> List[str]:
300301
categories = []
301302
for label in note.labels.all():
302303
categories.append(label.name)
303304
return categories
304305

305306

306-
def importPageWithCategories(notion: Client, note: node.TopLevelNode, root: Page, categories: dict[str, Page]) -> Page:
307+
def importPageWithCategories(notion: Client, note: node.TopLevelNode, root: Page, categories: Dict[str, Page]) -> Page:
307308
# Extract categories
308309
rootName = root.title
309310
cats = getNoteCategories(note)
@@ -362,8 +363,14 @@ def parseNote(note: node.TopLevelNode, page: Page, keep: Keep, config: Config):
362363

363364
def parseList(list: node.List, page: Page):
364365
item: node.ListItem
365-
for item in list.items: # type: node.ListItem
366-
page.add_todo(item.text, item.checked)
366+
for item in list.items:
367+
while item.text:
368+
# Take the first 1500 characters or less, notion sets max todo length to 2000
369+
# so we take 1500 to be safe in case of emojis which take more
370+
chunk = item.text[:1500]
371+
item.text = item.text[1500:] if len(item.text) > 1500 else ""
372+
# Add a new to-do item with the chunk of text
373+
page.add_todo(chunk, item.checked)
367374

368375

369376
def url2uuid(url: str) -> str:
@@ -425,19 +432,49 @@ def url2uuid(url: str) -> str:
425432
gnotes = keep.all()
426433

427434
i = 0
428-
for gnote in gnotes:
435+
max_retries = 3 # Retry mechanism
436+
retry_delay = 2
437+
while i < 2056:
438+
gnote = gnotes[i]
429439
i += 1
430-
if isinstance(gnote, node.List):
431-
if not config.import_todos:
432-
continue
433-
print(f'Importing TODO #{i}: {gnote.title}')
434-
page = importPageWithCategories(notion, gnote, todos, categories)
435-
parseList(gnote, page)
436-
create_page(notion, page)
437-
else:
438-
if not config.import_notes:
439-
continue
440-
print(f'Importing note #{i}: {gnote.title}')
441-
page = importPageWithCategories(notion, gnote, notes, categories)
442-
parseNote(gnote, page, keep, config)
443-
create_page(notion, page)
440+
try:
441+
if isinstance(gnote, node.List):
442+
if not config.import_todos:
443+
continue
444+
print(f'Importing TODO #{i}: {gnote.title}')
445+
page = importPageWithCategories(notion, gnote, todos, categories)
446+
parseList(gnote, page)
447+
create_page(notion, page)
448+
else:
449+
if not config.import_notes:
450+
continue
451+
print(f'Importing note #{i}: {gnote.title}')
452+
page = importPageWithCategories(notion, gnote, notes, categories)
453+
parseNote(gnote, page, keep, config)
454+
create_page(notion, page)
455+
except errors.APIResponseError as e:
456+
if e.code == 400:
457+
retries = 0
458+
while retries < max_retries:
459+
print(f"Retrying request after {retry_delay} seconds...")
460+
time.sleep(retry_delay)
461+
try:
462+
# Retry the request
463+
if isinstance(gnote, node.List):
464+
page = importPageWithCategories(notion, gnote, todos, categories)
465+
parseList(gnote, page)
466+
create_page(notion, page)
467+
else:
468+
page = importPageWithCategories(notion, gnote, notes, categories)
469+
parseNote(gnote, page, keep, config)
470+
create_page(notion, page)
471+
break # Exit the retry loop if successful
472+
except errors.APIResponseError as e:
473+
if e.code == 400:
474+
retries += 1
475+
else:
476+
raise # If the error is not a 400, raise it immediately
477+
else:
478+
raise # Raise the error if maximum retries are exceeded
479+
else:
480+
raise # If the error is not a 400, raise it immediately

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ gkeepapi
22
keyring
33
notion-client>=2.0.0
44
requests<2.30.0
5+
notion
6+
tqdm

0 commit comments

Comments
 (0)