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

1"""Puzzletree CLI application entry point. 

2 

3------------------------ 

4 

5This module defines the main Typer-based CLI application for Puzzletree. 

6It serves as the entry point for the tile and reconstruct commands. 

7 

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 

14 

15Behavior: 

16- When run with no arguments, displays help. 

17- Common options include verbosity, dry-run simulation, theme selection, and version/debug flags. 

18 

19Example usage: 

20 

21 python -m puzzletree.cli --version 

22 python -m puzzletree.cli --debug-info 

23 

24Dependencies: 

25- typer 

26- pydantic 

27- pydantic-settings 

28- rich 

29""" 

30 

31import logging # noqa: I001 - Import order is correct; isort may flag due to template variable substitution 

32 

33from pydantic import ValidationError 

34from rich.console import Console 

35from rich.text import Text 

36from typer import Context, Exit, Option, Typer 

37 

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 

43 

44 

45cli_app = Typer(add_completion=True, invoke_without_command=True, no_args_is_help=True) 

46 

47 

48# Register all commands dynamically 

49_register_commands(cli_app) 

50 

51 

52def _version_callback(value: bool) -> None: 

53 """Print model version information. 

54 

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) 

64 

65 

66def _debug_info_callback(value: bool) -> None: 

67 """Print debug information. 

68 

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) 

78 

79 

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() 

103 

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) 

112 

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 

119 

120 ctx.obj = { 

121 "verbose": verbose, 

122 "dry_run": dry_run, 

123 "theme": theme, 

124 "config": config, 

125 }