Skip to content

Commit e4c70c3

Browse files
committed
Change LeetCode get_submission method into a generator to avoid API rate limit problems
1 parent b96d01c commit e4c70c3

File tree

4 files changed

+58
-62
lines changed

4 files changed

+58
-62
lines changed

README.md

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ section [Docker Image here](#docker-image).
2525

2626
To use `leetcode-export` you can either download it from pypi.org or you can clone this repository.
2727

28-
## Download from pypi.org
28+
### Download from pypi.org
2929

30-
Run `pip install leetcode-export` to download it and install all the needed dependencies. You might need to use `pip3`
31-
depending on the configuration of your system.
30+
Run `pip install leetcode-export` to install leetcode-export, you might have to use `pip3` of your system. To use the
31+
script run `leetcode-export`, optionally supply the script arguments, for more instructions read the
32+
section [script arguments here](#script-arguments).
3233

3334
### Clone the repository
3435

@@ -44,14 +45,14 @@ Install all the needed dependencies:
4445
pip install -r requirements.txt
4546
```
4647

47-
Now you can either install it or just execute it:
48+
You can either install leetcode-export in your system or just execute it:
4849

49-
- To install leetcode-export in your system:
50+
- To install it run:
5051
```bash
5152
python setup.py install
5253
```
5354

54-
- To run the project without installing it:
55+
- To execute the script without installing it:
5556
```bash
5657
python -m leetcode_export --folder submissions
5758
```
@@ -70,6 +71,25 @@ Download all your LeetCode submission in the current folder:
7071
docker run -it -v $(pwd):/usr/app/out --rm nevermendel/leetcode-export
7172
```
7273

74+
## Login
75+
76+
To download your submissions you need to log in your LeetCode account by providing the cookies. To log in using cookies,
77+
you need to get them from a session where you are already logged in.
78+
79+
**Steps required**:
80+
81+
- Login in your LeetCode account in your browser
82+
- Open the browser's Dev Tool
83+
- Click on the Network tab
84+
- Copy the cookie header that can be found under Request Headers in any leetcode.com request.
85+
86+
You can insert the cookie string that you have just copied in the interactive menu (recommended) or you can pass it as a
87+
program argument when lunching the script, like in the following example:
88+
89+
```bash
90+
python leetcode-export --cookies {COOKIES}
91+
```
92+
7393
## Script arguments
7494
7595
The script accepts the following arguments:
@@ -93,24 +113,6 @@ optional arguments:
93113
Submission filename format
94114
```
95115
96-
## Login
97-
98-
To download your submissions you need to log in your LeetCode account by providing the cookies. To log in using cookies,
99-
you need to get them from a session where you are already logged in.
100-
101-
**Steps required**:
102-
- Login in your LeetCode account in your browser
103-
- Open the browser's Dev Tool
104-
- Click on the Network tab
105-
- Copy the cookie header that can be found under Request Headers in any leetcode.com request.
106-
107-
You can insert the cookie string that you have just copied in the interactive menu (recommended) or you can pass it as a
108-
program argument when lunching the script, like in the following example:
109-
110-
```bash
111-
python leetcode-export --cookies {COOKIES}
112-
```
113-
114116
Using the interactive menu is preferred as it will avoid storing your cookies in the command history.
115117
116118
## Filename template arguments
@@ -166,7 +168,6 @@ date_formatted: str
166168
extension: str
167169
```
168170
169-
170171
Default submission filename
171172
template: `${date_formatted} - ${status_display} - runtime ${runtime} - memory ${memory}.${extension}`
172173

leetcode_export/__main__.py

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
import logging
44
import os
55
from string import Template
6-
from typing import List, Dict
6+
from typing import Set
77

88
from leetcode_export.leetcode import LeetCode
9-
from leetcode_export.leetcode_rest import Submission
109

1110
PROBLEM_CONTENT_TEMPLATE = Template('''${question_id} - ${title}
1211
${difficulty} - https://leetcode.com/problems/${title_slug}/
@@ -70,31 +69,30 @@ def main():
7069
os.mkdir(args.folder)
7170
os.chdir(args.folder)
7271

73-
submissions: Dict[str, List[Submission]] = leetcode.get_submissions()
74-
75-
for slug in submissions:
76-
logging.info(f"Processing {slug}")
77-
if not os.path.exists(slug):
78-
os.mkdir(slug)
72+
written_problems: Set[str] = set()
73+
74+
for submission in leetcode.get_submissions():
75+
if not os.path.exists(submission.title_slug):
76+
os.mkdir(submission.title_slug)
77+
os.chdir(submission.title_slug)
78+
79+
if submission.title_slug not in written_problems:
80+
problem = leetcode.get_problem(submission.title_slug)
81+
info_filename = problem_template.substitute(**problem.__dict__)
82+
if not os.path.exists(info_filename):
83+
info_file = open(info_filename, 'w+')
84+
info_file.write(PROBLEM_CONTENT_TEMPLATE.substitute(**problem.__dict__))
85+
info_file.close()
86+
written_problems.add(submission.title_slug)
87+
88+
sub_filename = submission_template.substitute(**submission.__dict__)
89+
if not os.path.exists(sub_filename):
90+
logging.info(f"Writing {submission.title_slug}/{sub_filename}")
91+
sub_file = open(sub_filename, 'w+')
92+
sub_file.write(submission.code)
93+
sub_file.close()
7994
else:
80-
logging.info(f"Folder {slug} already exists")
81-
os.chdir(slug)
82-
problem_description = leetcode.get_problem(slug)
83-
info_filename = problem_template.substitute(**problem_description.__dict__)
84-
if not os.path.exists(info_filename):
85-
info_file = open(info_filename, 'w+')
86-
info_file.write(PROBLEM_CONTENT_TEMPLATE.substitute(**problem_description.__dict__))
87-
info_file.close()
88-
89-
for sub in submissions[slug]:
90-
sub_filename = submission_template.substitute(**sub.__dict__)
91-
if not os.path.exists(sub_filename):
92-
logging.info(f"Writing {slug}/{sub_filename}")
93-
sub_file = open(sub_filename, 'w+')
94-
sub_file.write(sub.code)
95-
sub_file.close()
96-
else:
97-
logging.info(f"{slug}/{sub_filename} already exists, skipping it")
95+
logging.info(f"{submission.title_slug}/{sub_filename} already exists, skipping it")
9896

9997
os.chdir("..")
10098

leetcode_export/leetcode.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import datetime
22
import logging
33
from time import sleep
4-
from typing import Dict, List
4+
from typing import Dict, Iterator
55

66
import requests
77

@@ -85,15 +85,15 @@ def get_problem(self, slug: str) -> Problem:
8585
problem_dict = dict_camelcase_to_snakecase(response.json()['data']['question'])
8686
return Problem.from_dict(problem_dict)
8787

88-
def get_submissions(self) -> Dict[str, List[Submission]]:
88+
def get_submissions(self) -> Iterator[Submission]:
8989
'''
90-
Get list of submission for logged user
91-
:return: Dict[str, List[Submission]], dictionary with slug as key and submission for given problem as value
90+
Get submissions for logged user
91+
:return: Iterator[Submission], LeetCode submission
9292
'''
9393
if not self.is_user_logged():
9494
logging.warning("Trying to get user submissions while user is not logged in")
95-
return {}
96-
dictionary: Dict[str, List[Submission]] = {}
95+
return None
96+
9797
current = 0
9898
response_json: Dict = {'has_next': True}
9999
while 'detail' not in response_json and 'has_next' in response_json and response_json['has_next']:
@@ -112,12 +112,9 @@ def get_submissions(self) -> Dict[str, List[Submission]]:
112112
if type(submission_dict[key]) == str and key != 'url' and key != 'code':
113113
submission_dict[key] = remove_special_characters(submission_dict[key])
114114
submission = Submission.from_dict(submission_dict)
115-
if submission.title_slug not in dictionary:
116-
dictionary[submission.title_slug] = []
117-
dictionary[submission.title_slug].append(submission)
115+
yield submission
118116

119117
current += 20
120118
sleep(1)
121119
if 'detail' in response_json:
122120
logging.warning(response_json['detail'])
123-
return dictionary

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setup(
77
name='leetcode-export',
8-
version='1.1',
8+
version='1.1.1',
99
url='https://github.com/NeverMendel/leetcode-export',
1010
license='MIT',
1111
author='Davide Cazzin',

0 commit comments

Comments
 (0)