Coverage for src / puzzletree / cli / main_cli.py: 93.33%
39 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-12 20:35 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-12 20:35 +0000
1"""Puzzletree CLI application entry point.
3------------------------
5This module defines the main Typer-based CLI application for Puzzletree.
6It serves as the entry point for the tile and reconstruct commands.
8Features:
9- Uses `Typer` for CLI structure and command dispatch.
10- Employs `pydantic-settings` for configuration management.
11- Integrates with `Rich` for improved terminal output formatting and theming.
12- Displays version and debug information.
13- Supports subcommands like
15Behavior:
16- When run with no arguments, displays help.
17- Common options include verbosity, dry-run simulation, theme selection, and version/debug flags.
19Example usage:
21 python -m puzzletree.cli --version
22 python -m puzzletree.cli --debug-info
24Dependencies:
25- typer
26- pydantic
27- pydantic-settings
28- rich
29"""
31import logging # noqa: I001 - Import order is correct; isort may flag due to template variable substitution
33from pydantic import ValidationError
34from rich.console import Console
35from rich.text import Text
36from typer import Context, Exit, Option, Typer
38from puzzletree._version import debug_info, version_info
39from puzzletree.cli.register import _register_commands
40from puzzletree.config import Config
41from puzzletree.utils.logging import get_logger_console
42from puzzletree.utils.theme.theme import set_theme
45cli_app = Typer(add_completion=True, invoke_without_command=True, no_args_is_help=True)
48# Register all commands dynamically
49_register_commands(cli_app)
52def _version_callback(value: bool) -> None:
53 """Print model version information.
55 Parameters
56 ----------
57 value: bool
58 Whether to print version information
59 """
60 if value:
61 console = Console(theme=set_theme("dark"))
62 console.print(version_info())
63 raise Exit(0)
66def _debug_info_callback(value: bool) -> None:
67 """Print debug information.
69 Parameters
70 ----------
71 value: bool
72 Whether to print debug information
73 """
74 if value:
75 console = Console(theme=set_theme("dark"))
76 debug_info(console)
77 raise Exit(0)
80@cli_app.callback(invoke_without_command=True, no_args_is_help=True)
81def main(
82 ctx: Context,
83 dry_run: bool | None = Option(False, "--dry-run", help="Show changes but do not execute them"),
84 verbose: bool | None = Option(False, "--verbose", "-v", help="verbose mode"),
85 version: bool | None = Option( # noqa: ARG001 - Handled by callback
86 None,
87 "--version",
88 help="check model version",
89 callback=_version_callback,
90 is_eager=True,
91 ),
92 debug_info: bool | None = Option( # noqa: ARG001 - Handled by callback
93 None,
94 "--debug-info",
95 help="Print debug information",
96 callback=_debug_info_callback,
97 is_eager=True,
98 ),
99 theme: str | None = Option("dark", "--theme", help="Set the theme, 'light' or 'dark' "),
100) -> None:
101 r"""Welcome to Puzzletree."""
102 logger, _ = get_logger_console()
104 config: Config | None = None
105 try:
106 config = Config()
107 if verbose: 107 ↛ 108line 107 didn't jump to line 108 because the condition on line 107 was never true
108 logger.setLevel(logging.DEBUG)
109 logger.info(Text("Setting verbose mode ON", style="orange"))
110 else:
111 logger.setLevel(logging.INFO)
113 logger.debug(config.model_dump())
114 logger.debug(Text("Configuration set", style="yellow"))
115 except ValidationError:
116 logger.exception("Unable to load configuration: ")
117 logger.exception("Obtained the following validating Errors loading configuration")
118 config = None
120 ctx.obj = {
121 "verbose": verbose,
122 "dry_run": dry_run,
123 "theme": theme,
124 "config": config,
125 }