From 851fabe76ecad8cd7098947dc1b3ba1ade9ded04 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 16:00:19 +0800 Subject: [PATCH] Import turtle lazily so tests run without a Tk library CI on the runner failed at collection: libtk8.6 is missing, so importing us_states_game.main imported turtle and tkinter. turtle is now imported when TurtleScreen is created. Task: MIL-003#7 --- src/us_states_game/turtle_screen.py | 13 ++++++++++--- tests/test_main.py | 13 +++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/us_states_game/turtle_screen.py b/src/us_states_game/turtle_screen.py index 7505536..8760d9a 100644 --- a/src/us_states_game/turtle_screen.py +++ b/src/us_states_game/turtle_screen.py @@ -1,11 +1,13 @@ """Turtle implementation of the game screen. @file turtle_screen.py -@brief The only module that imports turtle; draws the map and asks questions. +@brief The only module that uses turtle; draws the map and asks questions. + +turtle is imported when `TurtleScreen` is created, not when this module is +imported, so the rest of the program and its tests need no Tk library. """ import logging -import turtle from us_states_game.constants import ( LOGGER_NAME, @@ -34,7 +36,12 @@ class TurtleScreen: """Game screen drawn with Turtle graphics; implements `GameScreen`.""" def __init__(self) -> None: - """Open the window with the blank map.""" + """Open the window with the blank map. + + turtle (and so Tk) is imported here, at runtime. + """ + import turtle # noqa: PLC0415 # deferred: Tk may be missing at import time + self.screen = turtle.Screen() self.screen.setup(SCREEN_WIDTH, SCREEN_HEIGHT) self.screen.title(SCREEN_TITLE) diff --git a/tests/test_main.py b/tests/test_main.py index 2cb9c62..ebca005 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -89,3 +89,16 @@ def test_game_and_states_modules_do_not_import_turtle() -> None: ) result = subprocess.run([sys.executable, "-c", code], check=False) assert result.returncode == 0 + + +def test_main_imports_without_tk_library() -> None: + src = Path(__file__).resolve().parent.parent / "src" + code = ( + "import sys; " + "sys.modules['tkinter'] = None; sys.modules['_tkinter'] = None; " + f"sys.path.insert(0, {str(src)!r}); " + "import us_states_game.main, us_states_game.turtle_screen; " + "sys.exit(1 if 'turtle' in sys.modules else 0)" + ) + result = subprocess.run([sys.executable, "-I", "-c", code], check=False) + assert result.returncode == 0