Skip to content

Commit 9fd24da

Browse files
committed
Extend cli with possibility to specify directories for: templates, challenges solutions, and data
1 parent b1346f7 commit 9fd24da

File tree

5 files changed

+99
-21
lines changed

5 files changed

+99
-21
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
55

66
## Unreleased
7+
### Added
8+
- Extend cli with possibility to specify directories for: templates, challenges solutions, and data
9+
710
### Fixed
811
- Fixed typing in cli module
912
- Adapt ruff config for a newer version

src/aoc/main.py

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import shutil
33
from datetime import datetime
44
from pathlib import Path
5-
from typing import Literal
5+
from typing import Annotated, Literal
66

77
import aocd
88
import pytest
@@ -136,7 +136,8 @@ def verify(
136136
)
137137
raise typer.Exit(1)
138138
del locals()["module"]
139-
pytest_args.append(module.__file__)
139+
pytest_args.append(module.__path__[0])
140+
print(pytest_args)
140141
pytest.main(pytest_args)
141142

142143

@@ -191,26 +192,50 @@ def submit(
191192

192193
@app.command()
193194
def new_day(
194-
day: int = typer.Argument(help="Day for which to create a directory."),
195-
year: int = typer.Option(
196-
get_current_aoc_year(),
197-
"--year",
198-
"-y",
199-
help="Year for which to get the puzzle data",
200-
),
201-
force: bool = typer.Option(
202-
False,
203-
"--force",
204-
"-f",
205-
help="Force creation of directory even if it already exists.",
206-
),
195+
day: Annotated[int, typer.Argument(help="Day for which to create a directory.")],
196+
year: Annotated[
197+
int,
198+
typer.Option(
199+
"-y",
200+
"--year",
201+
help="Year for which to get the puzzle data",
202+
),
203+
] = get_current_aoc_year(),
204+
directory: Annotated[
205+
Path,
206+
typer.Option(
207+
...,
208+
"-d",
209+
"--directory",
210+
help="Path to a directory with challenges",
211+
),
212+
] = "src/aoc",
213+
data_directory: Annotated[
214+
Path,
215+
typer.Option(help="Path to a directory with data."),
216+
] = "data",
217+
template_directory: Annotated[
218+
Path,
219+
typer.Option(
220+
"--template-directory",
221+
help="Path to a template directory for a single day challenge.",
222+
),
223+
] = Path(__file__).parent / "templates/day_template",
224+
force: Annotated[
225+
bool,
226+
typer.Option(
227+
"--force",
228+
"-f",
229+
help="Force creation of directory even if it already exists.",
230+
),
231+
] = False,
207232
):
208233
"""Create a directory for a new day challenge."""
209234
puzzle = get_puzzle_object(year, day)
210235
if day < 1 or day > 25:
211236
typer.echo(typer.style("Day must be between 1 and 25.", fg=typer.colors.RED))
212237
raise typer.Exit(1)
213-
destination = Path(f"src/aoc/day_{day:02}")
238+
destination = directory.joinpath(f"day_{day:02}")
214239
if destination.exists() and not force:
215240
typer.echo(
216241
typer.style(
@@ -219,14 +244,13 @@ def new_day(
219244
)
220245
)
221246
raise typer.Exit(1)
222-
shutil.copytree(
223-
"templates/day_template", f"src/aoc/day_{day:02}", dirs_exist_ok=force
224-
)
247+
shutil.copytree(template_directory, destination, dirs_exist_ok=force)
225248
typer.echo(
226249
typer.style(f"Created solution directory for day {day}.", fg=typer.colors.GREEN)
227250
)
251+
data_directory.mkdir(exist_ok=True)
228252
if (
229-
real_input_data := Path(f"data/{day:02}_input.txt")
253+
real_input_data := data_directory.joinpath(f"{day:02}_input.txt")
230254
).exists() and real_input_data.stat().st_size:
231255
typer.echo(
232256
typer.style(
@@ -241,7 +265,7 @@ def new_day(
241265
typer.style(f"Created input data for day {day}.", fg=typer.colors.GREEN)
242266
)
243267
if (
244-
test_input_data := Path(f"data/{day:02}_test_input.txt")
268+
test_input_data := data_directory.joinpath(Path(f"{day:02}_test_input.txt"))
245269
).exists() and test_input_data.stat().st_size:
246270
typer.echo(
247271
typer.style(
File renamed without changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from aoc.base_tests import BaseTestChallenge, Empty
2+
3+
from . import Challenge
4+
5+
6+
class TestChallenge(BaseTestChallenge):
7+
challenge_class = Challenge
8+
expected_results_from_test_data = (Empty, Empty)
9+
expected_results_from_real_data = (Empty, Empty)

tests/test_cli.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from pathlib import Path
2+
from unittest import mock
3+
4+
import pytest
5+
from aoc.main import app
6+
from aocd.models import Puzzle
7+
from typer.testing import CliRunner
8+
9+
runner = CliRunner()
10+
11+
12+
@pytest.fixture(autouse=True)
13+
def m_aocd_puzzle(monkeypatch):
14+
m_puzzle = mock.Mock(spec=Puzzle)
15+
m_puzzle.input_data = "1"
16+
m_puzzle.examples = [mock.Mock(input_data="2")]
17+
monkeypatch.setattr("aoc.main.get_puzzle_object", mock.Mock(return_value=m_puzzle))
18+
return m_puzzle
19+
20+
21+
class TestSettingUpNewDay:
22+
def test_setting_up_new_day_creates_directories_in_configured_places(
23+
self, tmp_path: Path
24+
):
25+
result = runner.invoke(
26+
app,
27+
[
28+
"new-day",
29+
"11",
30+
"--data-directory",
31+
str(tmp_path / "data"),
32+
"--directory",
33+
str(tmp_path / "src"),
34+
],
35+
)
36+
if result.exception:
37+
raise result.exception
38+
assert result.exit_code == 0, result.exc_info
39+
40+
assert (tmp_path / "data" / "11_input.txt").read_text() == "1"
41+
assert (tmp_path / "data" / "11_test_input.txt").read_text() == "2"
42+
assert (tmp_path / "src" / "day_11").exists()

0 commit comments

Comments
 (0)