Files
aoc-py/aoc/input_file.py

140 lines
3.4 KiB
Python

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")