11#!/usr/bin/env python3
2-
32import argparse
43import asyncio
4+ import functools
55import json
66import logging
77import os
88import time
99from 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
1111
1212import diskcache
1313# https://github.com/kerrickstaley/genanki
1414import genanki # type: ignore
1515# https://github.com/prius/python-leetcode
1616import leetcode # type: ignore
17+ import urllib3
1718from tqdm import tqdm
1819
1920cookies = {
@@ -47,6 +48,31 @@ def parse_args() -> argparse.Namespace:
4748 return args
4849
4950
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+
5076class LeetcodeData :
5177 def __init__ (self ) -> None :
5278
@@ -70,6 +96,7 @@ def __init__(self) -> None:
7096 os .mkdir (CACHE_DIR )
7197 self ._cache = diskcache .Cache (CACHE_DIR )
7298
99+ @retry (times = 3 , exceptions = (urllib3 .exceptions .ProtocolError ,), delay = 5 )
73100 async def _get_problem_data (self , problem_slug : str ) -> Dict [str , str ]:
74101 if problem_slug in self ._cache :
75102 return self ._cache [problem_slug ]
0 commit comments