python -m turtle_challenges <challenge> and the turtle-challenges command open a window, run the named challenge and wait for a click. square and dashed-line are registered; a missing Tk is reported with a hint instead of a traceback. Task: MIL-002#6
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
"""!
|
||||
@file __main__.py
|
||||
@brief Entry point of `python -m turtle_challenges`.
|
||||
"""
|
||||
|
||||
from turtle_challenges.cli import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,74 @@
|
||||
"""!
|
||||
@file cli.py
|
||||
@brief Command line: run one challenge in a turtle window.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from collections.abc import Callable, Sequence
|
||||
from functools import partial
|
||||
|
||||
from turtle_challenges.constants import (
|
||||
CHALLENGE_DASHED_LINE,
|
||||
CHALLENGE_NAMES,
|
||||
CHALLENGE_SQUARE,
|
||||
)
|
||||
from turtle_challenges.dashed_line import draw_dashed_line
|
||||
from turtle_challenges.pen import Pen
|
||||
from turtle_challenges.square import draw_square
|
||||
from turtle_challenges.window import (
|
||||
TurtleUnavailableError,
|
||||
create_pen,
|
||||
create_window,
|
||||
)
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
"""!
|
||||
@brief Build the argument parser of the command line.
|
||||
|
||||
@return A parser with the challenge name.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="turtle-challenges",
|
||||
description="Run one of the turtle challenges in a window. "
|
||||
"Click the window to close it.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"challenge",
|
||||
choices=CHALLENGE_NAMES,
|
||||
help="the challenge to run",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
def build_challenges(pen: Pen) -> dict[str, Callable[[], None]]:
|
||||
"""!
|
||||
@brief Bind every challenge to a turtle.
|
||||
|
||||
@param pen The turtle that draws.
|
||||
@return A mapping from the command line name to a function without
|
||||
arguments that draws the challenge.
|
||||
"""
|
||||
return {
|
||||
CHALLENGE_SQUARE: partial(draw_square, pen),
|
||||
CHALLENGE_DASHED_LINE: partial(draw_dashed_line, pen),
|
||||
}
|
||||
|
||||
|
||||
def main(argv: Sequence[str] | None = None) -> int:
|
||||
"""!
|
||||
@brief Run the challenge named on the command line.
|
||||
|
||||
@param argv Arguments without the program name; `sys.argv` if omitted.
|
||||
@return The exit status: 0 on success.
|
||||
"""
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
window = create_window()
|
||||
tim = create_pen()
|
||||
except TurtleUnavailableError as error:
|
||||
parser.exit(1, f"{parser.prog}: error: {error}\n")
|
||||
build_challenges(tim)[args.challenge]()
|
||||
window.exitonclick()
|
||||
return 0
|
||||
@@ -31,3 +31,15 @@ DASH_LENGTH = 10
|
||||
|
||||
## Challenge 2: length of the gap after each dash, in turtle units.
|
||||
GAP_LENGTH = 10
|
||||
|
||||
## Command line name of challenge 1.
|
||||
CHALLENGE_SQUARE = "square"
|
||||
|
||||
## Command line name of challenge 2.
|
||||
CHALLENGE_DASHED_LINE = "dashed-line"
|
||||
|
||||
## Names of the challenges on the command line, in the order of the course.
|
||||
CHALLENGE_NAMES: tuple[str, ...] = (
|
||||
CHALLENGE_SQUARE,
|
||||
CHALLENGE_DASHED_LINE,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user