Skip to content

Commit 429919a

Browse files
committed
Integrate advent-of-code-data to the template
1 parent 23454d2 commit 429919a

File tree

4 files changed

+195
-6
lines changed

4 files changed

+195
-6
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ aoc new-day <day>
3131
It will create a `src/aoc/day_<day>` directory with a `__init__.py` and a `test_solution.py` python files.
3232
It will also create text files for both test and real data in the `data/` directory.
3333

34+
#### NEW! Downloading input data
35+
36+
Now this template uses [advent-of-code-data](https://github.com/wimglenn/advent-of-code-data) package to download
37+
your personal input data. To use it you need to set `AOC_SESSION` environment variable to your session cookie value.
38+
You can find it in your [browser's dev tools](https://github.com/wimglenn/advent-of-code-wim/issues/1)
39+
after logging in to the Advent of Code website.
40+
3441
### Implementing a solution for a day
3542

3643
`BaseChallenge` class is provided to help you with the boilerplate code. By default, each day's solution inherits
@@ -100,6 +107,18 @@ package that will run tests for you after each change in the code.
100107
ptw src/aoc
101108
```
102109

110+
### Submitting solution
111+
112+
Thanks to [advent-of-code-data](https://github.com/wimglenn/advent-of-code-wim/issues/1) package, you can submit your
113+
solution directly from the command line.
114+
115+
```sh
116+
aoc submit <day> <part>
117+
```
118+
119+
Under the hood, it will run the solution for the given day and part,
120+
and submit the answer to the Advent of Code website.
121+
103122
## Development
104123

105124
* Clone this repository

poetry.lock

Lines changed: 100 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ aoc = 'aoc.main:app'
3030
[tool.poetry.dependencies]
3131
python = ">=3.11, <4.0"
3232
typer = "^0.9.0"
33+
advent-of-code-data = "^2.0.1"
3334

3435
[tool.poetry.group.dev.dependencies]
3536
mypy = "*"
@@ -101,3 +102,7 @@ warn_unused_ignores = true
101102
warn_redundant_casts = true
102103
warn_return_any = true
103104
check_untyped_defs = true
105+
106+
[[tool.mypy.overrides]]
107+
module = "aocd.*"
108+
ignore_missing_imports = true

src/aoc/main.py

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
from pathlib import Path
44
from typing import Optional
55

6+
import aocd
67
import pytest
78
import typer
9+
from aocd import AocdError
10+
from aocd.exceptions import PuzzleLockedError
11+
from aocd.models import Puzzle
812

913
app = typer.Typer(no_args_is_help=True)
1014

@@ -46,6 +50,35 @@ def run_challenge(day: int, test_data: bool):
4650
module.Challenge(use_test_data=False).run()
4751

4852

53+
def get_puzzle_object(day: int) -> Puzzle | None:
54+
try:
55+
puzzle = Puzzle(year=2023, day=day)
56+
return puzzle
57+
except AocdError:
58+
pass
59+
return None
60+
61+
62+
def write_example_data(puzzle, test_input_data):
63+
try:
64+
test_input_data.write_text(puzzle.examples[0].input_data)
65+
except PuzzleLockedError:
66+
echo(
67+
"Failed writing test input data. Puzzle data is not available yet.",
68+
fg=typer.colors.YELLOW,
69+
)
70+
71+
72+
def write_input_data(puzzle, real_input_data):
73+
try:
74+
real_input_data.write_text(puzzle.input_data)
75+
except PuzzleLockedError:
76+
echo(
77+
"Failed writing user input data. Puzzle data is not available yet.",
78+
fg=typer.colors.YELLOW,
79+
)
80+
81+
4982
@app.command()
5083
def run(
5184
day: int = typer.Argument(..., help="Day of the challenge to run."),
@@ -93,10 +126,35 @@ def verify(
93126
raise typer.Exit(1)
94127
del locals()["module"]
95128
pytest_args.append(module.__file__)
96-
print(pytest_args)
97129
pytest.main(pytest_args)
98130

99131

132+
@app.command()
133+
def submit(
134+
day: int,
135+
part: str = typer.Argument(
136+
help="Which part of the solution to submit. "
137+
"You can use numbers 1/2 or letters a/b."
138+
),
139+
):
140+
if part in ("1", "2"):
141+
part = chr(ord("a") + int(part) - 1)
142+
if part not in ("a", "b"):
143+
typer.echo(
144+
typer.style(
145+
f"Invalid part {part}. Must be one of 1, 2, a, b.",
146+
fg=typer.colors.RED,
147+
)
148+
)
149+
raise typer.Exit(1)
150+
module = import_challenge_module(day)
151+
if part == "a":
152+
solution = module.Challenge(use_test_data=False).part_1()
153+
else:
154+
solution = module.Challenge(use_test_data=False).part_2()
155+
aocd.submit(solution, day=day, year=2023, part=part)
156+
157+
100158
@app.command()
101159
def new_day(
102160
day: int = typer.Argument(help="Day for which to create a directory."),
@@ -108,14 +166,15 @@ def new_day(
108166
),
109167
):
110168
"""Create a directory for a new day challenge."""
169+
puzzle = get_puzzle_object(day)
111170
if day < 1 or day > 25:
112171
typer.echo(typer.style("Day must be between 1 and 25.", fg=typer.colors.RED))
113172
raise typer.Exit(1)
114173
destination = Path(f"src/aoc/day_{day:02}")
115174
if destination.exists() and not force:
116175
typer.echo(
117176
typer.style(
118-
f"Day {day} already exists. Add -f flag if you want to ovewrite",
177+
f"Day {day} already exists. Add -f flag if you want to overwrite",
119178
fg=typer.colors.RED,
120179
)
121180
)
@@ -126,26 +185,33 @@ def new_day(
126185
typer.echo(
127186
typer.style(f"Created solution directory for day {day}.", fg=typer.colors.GREEN)
128187
)
129-
if (real_input_data := Path(f"data/{day:02}_input.txt")).exists():
188+
if (
189+
real_input_data := Path(f"data/{day:02}_input.txt")
190+
).exists() and real_input_data.stat().st_size:
130191
typer.echo(
131192
typer.style(
132193
f"Input data already exists for day {day}.", fg=typer.colors.YELLOW
133194
)
134195
)
135196
else:
136197
real_input_data.touch()
198+
if puzzle is not None:
199+
write_input_data(puzzle, real_input_data)
137200
typer.echo(
138201
typer.style(f"Created input data for day {day}.", fg=typer.colors.GREEN)
139202
)
140-
real_input_data.touch()
141-
if (test_input_data := Path(f"data/{day:02}_test_input.txt")).exists():
203+
if (
204+
test_input_data := Path(f"data/{day:02}_test_input.txt")
205+
).exists() and test_input_data.stat().st_size:
142206
typer.echo(
143207
typer.style(
144208
f"Test input data already exists for day {day}.", fg=typer.colors.YELLOW
145209
)
146210
)
147211
else:
148212
test_input_data.touch()
213+
if puzzle is not None and puzzle.examples:
214+
write_example_data(puzzle, test_input_data)
149215
typer.echo(
150216
typer.style(
151217
f"Created test input data for day {day}.", fg=typer.colors.GREEN

0 commit comments

Comments
 (0)