1818from termcolor import cprint
1919
2020
21- __version__ = ' 0.5'
21+ __version__ = " 0.5"
2222
2323
2424log = getLogger (__name__ )
2525
2626
27- URI = ' http://adventofcode.com/{year}/day/{day}/'
28- AOC_TZ = pytz .timezone (' America/New_York' )
29- CONF_FNAME = os .path .expanduser (' ~/.config/aocd/token' )
30- MEMO_FNAME = os .path .expanduser (' ~/.config/aocd/{session}/{year}/{day}.txt' )
27+ URI = " http://adventofcode.com/{year}/day/{day}/"
28+ AOC_TZ = pytz .timezone (" America/New_York" )
29+ CONF_FNAME = os .path .expanduser (" ~/.config/aocd/token" )
30+ MEMO_FNAME = os .path .expanduser (" ~/.config/aocd/{session}/{year}/{day}.txt" )
3131RATE_LIMIT = 4 # seconds between consecutive requests
32- USER_AGENT = ' aocd.py/v{}' .format (__version__ )
32+ USER_AGENT = " aocd.py/v{}" .format (__version__ )
3333
3434
3535class AocdError (Exception ):
3636 pass
3737
3838
3939def eprint (* args , ** kwargs ):
40- cprint (* args , color = ' red' , file = sys .stderr , ** kwargs )
40+ cprint (* args , color = " red" , file = sys .stderr , ** kwargs )
4141
4242
4343def get_data (session = None , day = None , year = None ):
@@ -53,7 +53,7 @@ def get_data(session=None, day=None, year=None):
5353 if year is None :
5454 year = guess_year ()
5555 log .info ("guessed year=%s" , year )
56- uri = URI .format (year = year , day = day ) + ' input'
56+ uri = URI .format (year = year , day = day ) + " input"
5757 memo_fname = MEMO_FNAME .format (session = session , year = year , day = day )
5858 try :
5959 # use previously received data, if any existing
@@ -65,23 +65,21 @@ def get_data(session=None, day=None, year=None):
6565 raise
6666 log .info ("getting data year=%s day=%s" , year , day )
6767 t = time .time ()
68- delta = t - getattr (get_data , ' last_request' , t - RATE_LIMIT )
68+ delta = t - getattr (get_data , " last_request" , t - RATE_LIMIT )
6969 t_sleep = max (RATE_LIMIT - delta , 0 )
7070 if t_sleep > 0 :
71- cprint (' You are being rate-limited.' , color = ' red' )
72- cprint (' Sleeping {} seconds...' .format (t_sleep ))
71+ cprint (" You are being rate-limited." , color = " red" )
72+ cprint (" Sleeping {} seconds..." .format (t_sleep ))
7373 time .sleep (t_sleep )
74- cprint (' Done.' )
74+ cprint (" Done." )
7575 response = requests .get (
76- url = uri ,
77- cookies = {'session' : session },
78- headers = {'User-Agent' : USER_AGENT },
76+ url = uri , cookies = {"session" : session }, headers = {"User-Agent" : USER_AGENT }
7977 )
8078 get_data .last_request = time .time ()
8179 if not response .ok :
8280 log .error ("got %s status code" , response .status_code )
8381 log .error (response .content )
84- raise AocdError (' Unexpected response' )
82+ raise AocdError (" Unexpected response" )
8583 data = response .text
8684 parent = os .path .dirname (memo_fname )
8785 try :
@@ -93,10 +91,10 @@ def get_data(session=None, day=None, year=None):
9391 except OSError as err :
9492 if err .errno != errno .EEXIST :
9593 raise
96- with open (memo_fname , 'w' ) as f :
94+ with open (memo_fname , "w" ) as f :
9795 log .info ("caching this data" )
9896 f .write (data )
99- return data .rstrip (' \r \n ' )
97+ return data .rstrip (" \r \n " )
10098
10199
102100def guess_year ():
@@ -110,7 +108,7 @@ def guess_year():
110108 if aoc_now .month < 12 :
111109 year -= 1
112110 if year < 2015 :
113- raise AocdError (' Time travel not supported yet' )
111+ raise AocdError (" Time travel not supported yet" )
114112 return year
115113
116114
@@ -121,14 +119,14 @@ def guess_day():
121119 """
122120 aoc_now = datetime .now (tz = AOC_TZ )
123121 if aoc_now .month != 12 :
124- raise AocdError (' guess_day is only available in December (EST)' )
122+ raise AocdError (" guess_day is only available in December (EST)" )
125123 day = min (aoc_now .day , 25 )
126124 return day
127125
128126
129127def get_cookie ():
130128 # export your session id as AOC_SESSION env var
131- cookie = os .getenv (' AOC_SESSION' )
129+ cookie = os .getenv (" AOC_SESSION" )
132130 if cookie :
133131 return cookie
134132
@@ -138,33 +136,35 @@ def get_cookie():
138136 cookie = f .read ().strip ()
139137 except (OSError , IOError ) as err :
140138 if err .errno != errno .ENOENT :
141- raise AocdError (' Wat' )
139+ raise AocdError (" Wat" )
142140 if cookie :
143141 return cookie
144142
145143 # heck, you can just paste it in directly here if you want:
146- cookie = ''
144+ cookie = ""
147145 if cookie :
148146 return cookie
149147
150- eprint (' ERROR: AoC session ID is needed to get your puzzle data!' )
151- eprint (' You can find it in your browser cookies after login.' )
152- eprint (' 1) Save the cookie into a text file {}, or' .format (CONF_FNAME ))
153- eprint (' 2) Export the cookie in environment variable AOC_SESSION' )
148+ eprint (" ERROR: AoC session ID is needed to get your puzzle data!" )
149+ eprint (" You can find it in your browser cookies after login." )
150+ eprint (" 1) Save the cookie into a text file {}, or" .format (CONF_FNAME ))
151+ eprint (" 2) Export the cookie in environment variable AOC_SESSION" )
154152
155- raise AocdError (' Missing session ID' )
153+ raise AocdError (" Missing session ID" )
156154
157155
158156def skip_frame (name ):
159157 basename = os .path .basename (name )
160- skip = any ([
161- name == __file__ ,
162- 'importlib' in name , # Python 3 import machinery
163- '/IPython/' in name , # ipython adds a tonne of stack frames
164- name .startswith ('<' ), # crap like <decorator-gen-57>
165- name .endswith ('ython3' ), # ipython3 alias
166- not re .search (r'[1-9]' , basename ), # no digits in filename
167- ])
158+ skip = any (
159+ [
160+ name == __file__ ,
161+ "importlib" in name , # Python 3 import machinery
162+ "/IPython/" in name , # ipython adds a tonne of stack frames
163+ name .startswith ("<" ), # crap like <decorator-gen-57>
164+ name .endswith ("ython3" ), # ipython3 alias
165+ not re .search (r"[1-9]" , basename ), # no digits in filename
166+ ]
167+ )
168168 return skip
169169
170170
@@ -179,34 +179,35 @@ def introspect_date():
179179 break shit, so don't do that. If you don't like weird frame hacks, just
180180 use the aocd.get_data() function and have a nice day!
181181 """
182- pattern_year = r' 201[5-9]'
183- pattern_day = r' 2[0-5]|1[0-9]|[1-9]'
182+ pattern_year = r" 201[5-9]"
183+ pattern_day = r" 2[0-5]|1[0-9]|[1-9]"
184184 stack = [f [0 ] for f in traceback .extract_stack ()]
185185 for name in stack :
186186 if not skip_frame (name ):
187187 abspath = os .path .abspath (name )
188188 break
189189 else :
190- raise AocdError (' Failed introspection of filename' )
190+ raise AocdError (" Failed introspection of filename" )
191191 years = {int (year ) for year in re .findall (pattern_year , abspath )}
192192 if len (years ) > 1 :
193- raise AocdError (' Failed introspection of year' )
193+ raise AocdError (" Failed introspection of year" )
194194 year = years .pop () if years else None
195- fname = re .sub (pattern_year , '' , abspath )
195+ fname = re .sub (pattern_year , "" , abspath )
196196 try :
197197 [n ] = set (re .findall (pattern_day , fname ))
198198 except ValueError :
199199 pass
200200 else :
201- assert not n .startswith ('0' ) # regex must prevent any leading 0
201+ assert not n .startswith ("0" ) # regex must prevent any leading 0
202202 n = int (n )
203203 if 1 <= n <= 25 :
204204 return n , year
205- raise AocdError (' Failed introspection of day' )
205+ raise AocdError (" Failed introspection of day" )
206206
207207
208208def is_interactive ():
209209 import __main__
210+
210211 try :
211212 __main__ .__file__
212213 except AttributeError :
@@ -216,36 +217,39 @@ def is_interactive():
216217
217218
218219def submit (answer , level , day = None , year = None , session = None , reopen = True ):
219- if level not in {1 , 2 , '1' , '2' }:
220- raise AocdError (' level must be 1 or 2' )
220+ if level not in {1 , 2 , "1" , "2" }:
221+ raise AocdError (" level must be 1 or 2" )
221222 if session is None :
222223 session = get_cookie ()
223224 if day is None :
224225 day = guess_day ()
225226 if year is None :
226227 year = guess_year ()
227- uri = URI .format (year = year , day = day ) + ' answer'
228+ uri = URI .format (year = year , day = day ) + " answer"
228229 log .info ("submitting %s" , uri )
229230 response = requests .post (
230231 uri ,
231- cookies = {' session' : session },
232- headers = {' User-Agent' : USER_AGENT },
233- data = {' level' : level , ' answer' : answer },
232+ cookies = {" session" : session },
233+ headers = {" User-Agent" : USER_AGENT },
234+ data = {" level" : level , " answer" : answer },
234235 )
235236 if not response .ok :
236237 log .error ("got %s status code" , response .status_code )
237238 log .error (response .content )
238- raise AocdError (' Non-200 response for POST: {}' .format (response ))
239- soup = bs4 .BeautifulSoup (response .text , ' html.parser' )
239+ raise AocdError (" Non-200 response for POST: {}" .format (response ))
240+ soup = bs4 .BeautifulSoup (response .text , " html.parser" )
240241 message = soup .article .text
241242 if "That's the right answer" in message :
242- color = ' green'
243+ color = " green"
243244 if reopen :
244245 webbrowser .open (response .url ) # So you can read part B on the website...
245246 elif "Did you already complete it" in message :
246- color = 'yellow'
247- elif "That's not the right answer" in message or "You gave an answer too recently" in message :
248- color = 'red'
247+ color = "yellow"
248+ elif (
249+ "That's not the right answer" in message
250+ or "You gave an answer too recently" in message
251+ ):
252+ color = "red"
249253 else :
250254 color = None
251255 cprint (soup .article .text , color = color )
0 commit comments