-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcreator.py
138 lines (113 loc) · 3.83 KB
/
creator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import argparse
import html
import os
import re
from datetime import date
from typing import List, Union
from p_tqdm import p_map
from leetcode_study_tool.formatters import FORMAT_MAP
from leetcode_study_tool.outputs import SAVE_MAP
from leetcode_study_tool.presets import PRESET_MAP
from leetcode_study_tool.queries import (
generate_session,
get_data,
get_neetcode_solution,
get_slug,
)
class ProblemsCreator:
"""
Create problems for Anki from the CLI inputs.
"""
def __init__(self, args: Union[argparse.Namespace, dict]) -> None:
self.format = "anki"
self.output = "output"
self.template = None
self.include_code = False
args = vars(args)
for key in args:
setattr(self, key, args[key])
if args.get("language"):
self.language = args["language"].strip().lower()
else:
self.language = None
if args.get("csrf"):
self.session = generate_session(args["csrf"])
else:
self.session = generate_session()
if args.get("url"):
self.urls = args["url"].split(",")
elif args.get("file"):
with open(args["file"], "r") as f:
self.urls = f.read().splitlines()
elif args.get("preset"):
self.urls = PRESET_MAP[args["preset"]]
def create_problems(self) -> None:
"""
Create the problems for Anki.
"""
problems = p_map(self._generate_problem, self.urls)
self._save_output(problems, self.output)
def _sanitize(self, input: Union[str, list, None]) -> Union[str, list]:
"""
Sanitize the given input to be Anki-compatible. This includes
removing delimeters with the desired Anki delimeter chosen
by the user.
Arguments
---------
input : str
The input to sanitize.
Returns
-------
str
The sanitized input.
"""
if input is None:
return ""
if isinstance(input, list):
return input
input = html.unescape(input)
input = re.sub(r"[;\n\r]", " ", input)
input = input.replace("</strong>", "</strong><br>")
input = re.sub(r"(<br>){2,}", "<br>", input)
return input
def _save_output(
self, problems: List[Union[List[Union[str, date]], None]], file: str
) -> None:
file_name = os.path.splitext(os.path.basename(file))[0]
SAVE_MAP[self.format](problems, file_name) # type: ignore
def _generate_problem(self, url: str) -> Union[str, None]:
"""
Generates a problem strings for the given URL in the requested format
Arguments
---------
url : str
The URL of the question to generate a problem for.
Returns
-------
str
The problem for the given URL.
"""
url = url.strip()
if not url:
return None
slug = get_slug(url)
try:
data = get_data(slug, self.language, self.session)
if (
self.include_code
and self.language
and not data.get("neetcode_solution")
):
github_solution = get_neetcode_solution(
data["id"], data["title"], self.language
)
if github_solution:
data["neetcode_solution"] = github_solution
except Exception as e:
print(f"Failed to generate problem for {url}: {e}")
return None
data = {k: self._sanitize(v) for k, v in data.items()}
if self.format == "anki":
return FORMAT_MAP[self.format](url, slug, data, self.template) # type: ignore
else:
return FORMAT_MAP[self.format](url, slug, data) # type: ignore