1
1
#!/usr/bin/env python3
2
-
3
2
import argparse
4
3
import asyncio
4
+ import functools
5
5
import json
6
6
import logging
7
7
import os
8
8
import time
9
9
from functools import lru_cache
10
- from typing import Any , Coroutine , Dict , Iterator , List , Tuple
10
+ from typing import Any , Callable , Coroutine , Dict , Iterator , List , Tuple
11
11
12
12
import diskcache
13
13
# https://github.com/kerrickstaley/genanki
14
14
import genanki # type: ignore
15
15
# https://github.com/prius/python-leetcode
16
16
import leetcode # type: ignore
17
+ import urllib3
17
18
from tqdm import tqdm
18
19
19
20
cookies = {
@@ -47,6 +48,31 @@ def parse_args() -> argparse.Namespace:
47
48
return args
48
49
49
50
51
+ def retry (times : int , exceptions : Tuple [Exception ], delay : float ) -> Callable :
52
+ """
53
+ Retry Decorator
54
+ Retries the wrapped function/method `times` times if the exceptions listed
55
+ in `exceptions` are thrown
56
+ """
57
+
58
+ def decorator (func ):
59
+ @functools .wraps (func )
60
+ async def wrapper (* args , ** kwargs ):
61
+ for attempt in range (times - 1 ):
62
+ try :
63
+ return await func (* args , ** kwargs )
64
+ except exceptions :
65
+ logging .exception (f"Exception occured, try { attempt + 1 } /{ times } " )
66
+ time .sleep (delay )
67
+
68
+ logging .error ("Last try" )
69
+ return await func (* args , ** kwargs )
70
+
71
+ return wrapper
72
+
73
+ return decorator
74
+
75
+
50
76
class LeetcodeData :
51
77
def __init__ (self ) -> None :
52
78
@@ -70,6 +96,7 @@ def __init__(self) -> None:
70
96
os .mkdir (CACHE_DIR )
71
97
self ._cache = diskcache .Cache (CACHE_DIR )
72
98
99
+ @retry (times = 3 , exceptions = (urllib3 .exceptions .ProtocolError ,), delay = 5 )
73
100
async def _get_problem_data (self , problem_slug : str ) -> Dict [str , str ]:
74
101
if problem_slug in self ._cache :
75
102
return self ._cache [problem_slug ]
0 commit comments