import datetime import pathlib import requests from aoc import exceptions def download(year: int, day: int, session_token: str | None) -> bytes: url = f"https://adventofcode.com/{year}/day/{day}/input" cookies = {} if session_token is not None: cookies["session"] = session_token response = requests.get(url, cookies=cookies) if response.status_code != 200: status = response.status_code # https://stackoverflow.com/a/39079819/11286805 local_tz = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo now = datetime.datetime.now(local_tz) release = datetime.datetime(year, 12, day, 5, tzinfo=datetime.UTC) if now < release: raise exceptions.AocError( f"unreleased input file {year}/{day:02} (http:{status})" ) raise exceptions.AocError( f"failed to fetch input file {year}/{day:02} (http:{status})" " - is AOC_SESSION_TOKEN environment variable set?" ) return response.content def create_input_file( year: int, day: int, session_token: str | None, path_base: pathlib.Path, force: bool = False, exist_ok: bool = False, ): path = path_base / str(year) / f"{day:02}.txt" path.parent.mkdir(parents=True, exist_ok=True) if path.exists() and not path.stat().st_size == 0: if exist_ok: return if not force: raise exceptions.AocError(f"input file {path} already exists") input_data = download(year, day, session_token) with open(path, "wb") as f: f.write(input_data) def get( year: int, day: int, path_base: pathlib.Path, ) -> str: path = path_base / str(year) / f"{day:02}.txt" path.parent.mkdir(parents=True, exist_ok=True) with open(path) as f: return f.read().rstrip("\n") def get_or_download( year: int, day: int, session_token: str | None, path_base: pathlib.Path, ) -> str: path = path_base / str(year) / f"{day:02}.txt" path.parent.mkdir(parents=True, exist_ok=True) create_input_file(year, day, session_token, path_base, exist_ok=True) return get(year, day, path_base) def _write_file_if_not_exists( path: pathlib.Path, exist_ok: bool = False, data: bytes | None = None ) -> None: path.parent.mkdir(parents=True, exist_ok=True) if path.exists() and not exist_ok: raise exceptions.AocError(f"{path} already exists") path.touch() if data is None: return with open(path, "wb") as f: f.write(data) _CREATE_TEMPLATE: bytes = b"""\ from typing import Any def part_1(input_data: str) -> Any: return None def part_2(input_data: str) -> Any: return None def test_part_1(example_data) assert part_1(example_data) == 0 def test_part_2(example_data) assert part_2(example_data) == 0 """ def create( year: int, day: int, solution_base: pathlib.Path, input_base: pathlib.Path, example_base: pathlib.Path, ) -> None: year_path = solution_base / f"year_{year}" year_path.mkdir(parents=True, exist_ok=True) _write_file_if_not_exists(year_path / "__init__.py", exist_ok=True) _write_file_if_not_exists(year_path / f"day_{day:02}.py", data=_CREATE_TEMPLATE) _write_file_if_not_exists(input_base / str(year) / f"{day:02}.txt") _write_file_if_not_exists(example_base / str(year) / f"{day:02}.txt")