Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boilerplate #2

Merged
merged 2 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added utils/__init__.py
Empty file.
67 changes: 67 additions & 0 deletions utils/create_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import argparse
import os

import aocd

from utils.file_data import FileData
from utils.templates.parser import create_parser_stub
from utils.templates.part import create_part_stub
from utils.templates.test_part import create_part_test_stub


def touch_file(path: str) -> None:
open(path, "x")


def write_file(path: str, content: str) -> None:
with open(path, "w") as f:
f.write(content.strip() + "\n")


def create_directories_if_needed(file_data: FileData) -> None:
if not os.path.isdir(file_data.directory):
os.makedirs(file_data.directory)
touch_file(file_data.src_init_file)
write_file(file_data.input_file, aocd.get_data(year=2023, day=file_data.day))
write_file(file_data.parser_file, create_parser_stub())
write_file(file_data.prompt_file, "")

if not os.path.isdir(file_data.test_directory):
os.makedirs(file_data.test_directory)
touch_file(file_data.test_init_file)


def create_part_files(file_data: FileData) -> None:
write_file(
file_data.part_file,
create_part_stub(day_string=file_data.day_string, part=file_data.part),
)

write_file(
file_data.test_part_file,
create_part_test_stub(day_string=file_data.day_string, part=file_data.part),
)


def create_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Helper to bootstrap files for problems"
)
parser.add_argument("-d", "--day", type=int, help="Day to create files for")
parser.add_argument(
"-p",
"--part",
choices=["a", "b"],
help="Part to create files for",
)

return parser


if __name__ == "__main__":
args = create_parser().parse_args()

file_data = FileData(day=args.day, part=args.part)

create_directories_if_needed(file_data)
create_part_files(file_data)
72 changes: 72 additions & 0 deletions utils/file_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import dataclasses
from typing import Literal, Union

Part = Union[Literal["a"], Literal["b"]]


@dataclasses.dataclass
class FileData(object):
"""Dataclass to handle any directory/file names
to be used when bootstrapping files
"""

src = "aoc_2023"
tests = "tests"

day: int
part: Part

@property
def day_string(self) -> str:
return f"{self.day:02d}"

@property
def part_module(self) -> str:
return f"{self.src}.day_{self.day_string}.{self.part}"

@property
def directory(self) -> str:
return f"{self.src}/day_{self.day_string}"

@property
def test_directory(self) -> str:
return f"{self.tests}/test_day_{self.day_string}"

@property
def input_file(self) -> str:
return f"{self.directory}/input.txt"

@property
def part_file(self) -> str:
return f"{self.directory}/{self.part}.py"

@property
def parser_file(self) -> str:
return f"{self.directory}/parser.py"

@property
def prompt_file(self) -> str:
return f"{self.directory}/from_prompt.py"

@property
def solver_file(self) -> str:
return f"{self.directory}/solver.py"

@property
def test_part_file(self) -> str:
return f"{self.test_directory}/test_{self.part}.py"

@property
def test_data_file(self) -> str:
return f"{self.test_directory}/sample_data.py"

@property
def src_init_file(self) -> str:
return self._init_file(self.directory)

@property
def test_init_file(self) -> str:
return self._init_file(self.test_directory)

def _init_file(self, directory: str) -> str:
return f"{directory}/__init__.py"
37 changes: 37 additions & 0 deletions utils/submit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import argparse
import subprocess

import aocd

from utils.file_data import FileData, Part


def submit(day: int, part: Part) -> None:
data_file = FileData(day=day, part=part)
completed_process = subprocess.run(
["python", "-m", data_file.part_module], capture_output=True
)
answer = completed_process.stdout.decode("utf-8").strip()

print(f"Submitting answer: {answer}")
assert not isinstance(aocd.submit, str)
aocd.submit(day=day, part=part, year=2023, answer=answer)


def create_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Helper to submit problems")
parser.add_argument("-d", "--day", type=int, help="Day to create files for")
parser.add_argument(
"-p",
"--part",
choices=["a", "b"],
help="Part to create files for",
)

return parser


if __name__ == "__main__":
args = create_parser().parse_args()

submit(day=args.day, part=args.part)
Empty file added utils/templates/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions utils/templates/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
def create_parser_stub() -> str:
return _PARSER_TEMPLATE


_PARSER_TEMPLATE = """
class Parser:
@staticmethod
def parse(input: str) -> str:
return input.strip()

"""
39 changes: 39 additions & 0 deletions utils/templates/part.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
def create_part_stub(day_string: str, part: str) -> str:
src = "aoc_2023"
return _PART_TEMPLATE.format(
day_string=day_string,
part_upper=part.upper(),
src=src,
)


_PART_TEMPLATE = """
from dataclasses import dataclass
from {src}.day_{day_string}.parser import Parser


@dataclass
class Day{day_string}Part{part_upper}Solver:
input: str

@property
def solution(self) -> int:
return -1


def solve(input: str) -> int:
data = Parser.parse(input)
solver = Day{day_string}Part{part_upper}Solver(data)

return solver.solution

def get_solution() -> int:
with open("aoc_2023/day_{day_string}/input.txt", "r") as f:
input = f.read()
return solve(input)


if __name__ == "__main__":
print(get_solution())

"""
30 changes: 30 additions & 0 deletions utils/templates/test_part.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
def create_part_test_stub(day_string: str, part: str) -> str:
src = "aoc_2023"
return _TEST_PART_TEMPLATE.format(
day_string=day_string,
part=part,
part_upper=part.upper(),
src=src,
)


_TEST_PART_TEMPLATE = """
import pytest

from {src}.day_{day_string}.{part} import get_solution, solve


@pytest.mark.parametrize(
"input, expected",
[
("INPUT", -1),
],
)
def test_solve(input: str, expected: int):
assert solve(input) == expected

@pytest.mark.skip
def test_my_solution():
assert get_solution() == "NOT THIS"

"""