-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathget_input.py
274 lines (213 loc) · 8.78 KB
/
get_input.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
"""Get the stuff from AoC"""
import argparse
import os
import re
import requests
from bs4 import BeautifulSoup
from dotenv import load_dotenv
try:
from gts_colors.colors import BLUE, BOLD, RESET, YELLOW
except ImportError:
__ESC__ = "\033["
BLUE = f"{__ESC__}34m"
BOLD = f"{__ESC__}1m"
RESET = f"{__ESC__}0m"
YELLOW = f"{__ESC__}33m"
def get_args() -> argparse.Namespace:
"""Setup arg parser and return optional and required args.
Returns:
argparse.Namespace: args
"""
parser = argparse.ArgumentParser(
f"\n{BLUE}{BOLD}"
"********************************************************************************\n" # noqa: E501
"********************************************************************************\n" # noqa: E501
"** **\n" # noqa: E501
"** Will get the input file and create a boilerplate python file for a given **\n" # noqa: E501
"** Advent of Code problem. **\n" # noqa: E501
"** **\n" # noqa: E501
"********************************************************************************\n" # noqa: E501
"********************************************************************************\n" # noqa: E501
f"{RESET}"
)
parser.add_argument("day", help="Enter the day for the problem you are working on.") # noqa: E501
parser.add_argument("-i", "--input", help="Create the input file.", action="store_true") # noqa: E501
parser.add_argument("-p", "--python", help="Create the python template.", action="store_true") # noqa: E501
parser.add_argument("-r", "--readme", help="Create the read me template.", action="store_true") # noqa: E501
return parser.parse_args()
def get_session_id() -> str:
"""Get the session ID from the .env file.
Returns:
str: session id for logged in user
"""
load_dotenv()
return os.getenv("SESSION_ID")
def get_input_data(url: str, session_id: str) -> list[str]:
"""Get the input data for the given url (day of advent of code)
Args:
url (str): url of the advent of code problem for a specific day
ID (str): session id for logged in user
Returns:
list[str]: the input for a given advent of code problem
"""
cookies = {
"session": session_id,
}
res = requests.get(f"{url}/input", cookies=cookies)
data = res.content.decode("UTF-8")
return data
def get_instruction_data(url: str, session_id: str) -> str:
"""Get the instruction text from the given url (day of advent of code)
Args:
url (str): url of the advent of code problem for a specific day
ID (str): session id for logged in user
Returns:
str: html text from the given url
"""
cookies = {
"session": session_id,
}
res = requests.get(f"{url}", cookies=cookies).text
html_text = BeautifulSoup(res, "html.parser").get_text()
return html_text
def format_instruction_text(html_text: str) -> str:
"""Get a pep8 formatted version of the given html_text.
Args:
html_text (str): all text from html object
Returns:
str: pep8 formatted set of instruction text
"""
# Save the text and format it.
# Not sure why it differs so much after saving and reading
# back from a file versus just doing html_text.split('\n')[18:-11]
with open("temp", "a+", encoding="utf-8") as python_file:
max_line_length = 79
instructions = []
# Checks for '--- message ---' and keeps a match of the inner text
# '--- message ---'
# 'message'
# [-]{3}[\s]{1} '--- '
# ([\s\w:!-]*) 'any characters, whitespace, colon, exclamation, hyphen'
# [\s]{1}[-]{3} ' ---'
regex_str = r"([-]{3}[\s]{1}([\s\w:!-]*)[\s]{1}[-]{3})"
regex = re.compile(regex_str)
matches = regex.findall(html_text)
title = matches[0][1]
for match in matches:
html_text = html_text.replace(match[0], f"\n\n--- {match[1]} ---\n")
# TODO: Prefer to format the html_text directly and not
# write to, and read back from, a file.
python_file.write(html_text)
python_file.seek(0) # back to the beginning.
lines = python_file.readlines()[18:-11] # Cut out the junk.
# Break the lines up such that they are never longer
# than MAX_LINE_LENGTH, for pep8
for line in lines:
start = 0
end = max_line_length
if max_line_length >= len(line):
instructions.append(line)
continue
while end < len(line):
while line[end] != " ":
end -= 1
instructions.append(line[start:end] + "\n")
start = end + 1
end += max_line_length
if end >= len(line):
instructions.append(line[start:] + "\n")
os.remove("temp")
return "".join(instructions), title
def fix_day(day: str) -> str:
"""Append a zero [0] in front of day if day is one digit.\n
1 -> 01
Args:
day (str): 1, 21, etc.
Returns:
str: 01, 21, etc.
"""
return f"0{day}" if len(day) == 1 else day
def try_make_dir(day: str) -> None:
"""Try to make a new directory for the given day.\n
./Day_01,\n
./Day_21,\n
etc.\n
If it exists, just print to console.
Args:
day (str): 01, 21, etc.
"""
if os.path.isdir(f"Day_{day}"):
print(f"{YELLOW}{BOLD}* Directory exists.{RESET}")
else:
os.mkdir(f"Day_{day}")
def make_input_file(day: str, data: list[str]) -> None:
"""Save the input data to a file for the given day in its
corresponding directory.
Args:
day (str): 01, 21, etc.
file (str): file name to save as
data (list[str]): the data to save to file
"""
if os.path.exists(f"Day_{day}/input.txt"):
print(f"{YELLOW}{BOLD}* Input file exists.{RESET}")
return
with open(f"Day_{day}/input.txt", "w", encoding="utf-8") as input_file:
input_file.write(data)
with open(f"Day_{day}/sample.txt", "a", encoding="utf-8"):
pass
def make_python_file(day: str, instructions: str) -> None:
"""Save the instruction string to a python file for the given
day in its corresponding directory. If the file exists, just
overwrite the previous instructions with new instructions that
include part 2.
Args:
day (str): 01, 21, etc.
instructions (str): instructions to be added at the top of python file
"""
# If we already made the file, just overwrite the instructions,
# keep the code we already wrote.
if os.path.exists(f"Day_{day}/day_{day}_problems.py"):
print(f"{YELLOW}{BOLD}python file exists, editing current file.{RESET}")
with open(f"Day_{day}/day_{day}_problems.py", "r+", encoding="utf-8") as python_file:
data = python_file.read()
previous_contents = data.split('"""', 2)
output = f"\"\"\"\n{instructions}\"\"\"{''.join(previous_contents[2:])}"
python_file.seek(0)
python_file.truncate(0)
python_file.write(output)
else:
with open(f"Day_{day}/day_{day}_problems.py", "w", encoding="utf-8") as python_file:
with open("py_template.txt", "r", encoding="utf-8") as template:
output = (template.read().replace("{day}", day).replace("{instructions}", instructions)) # noqa E501
python_file.write(output)
def update_readme(title: str) -> None:
"""Update readme
Args:
title (str: title extracted from isntruction text.
"""
with open("README.md", "a", encoding="utf-8") as readme_file:
with open("readme_template.txt", "r", encoding="utf-8") as template:
output = template.read().replace("{title}", title)
readme_file.write(output)
def main():
"""Main method"""
args = get_args()
aoc_url = f"https://adventofcode.com/2022/day/{args.day}"
session_id = get_session_id()
title = None
day = fix_day(args.day)
try_make_dir(day)
if args.input:
input_data = get_input_data(aoc_url, session_id)
make_input_file(day, input_data)
if args.python:
instruction_data = get_instruction_data(aoc_url, session_id)
instructions, title = format_instruction_text(instruction_data)
make_python_file(day, instructions)
if args.readme:
if title is None:
instruction_data = get_instruction_data(aoc_url, session_id)
instructions, title = format_instruction_text(instruction_data)
update_readme(title)
if __name__ == "__main__":
main()