Coverage for /home/runner/work/bijux-cli/bijux-cli/src/bijux_cli/commands/config/get.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.10.4, created at 2025-08-19 23:36 +0000

1# SPDX-License-Identifier: MIT 

2# Copyright © 2025 Bijan Mousavi 

3 

4"""Implements the `config get` subcommand for the Bijux CLI. 

5 

6This module contains the logic for retrieving the value of a specific key 

7from the active configuration store. It provides a structured, machine-readable 

8response containing the value or an error if the key is not found. 

9 

10Output Contract: 

11 * Success: `{"value": str}` 

12 * Verbose: Adds `{"python": str, "platform": str}` to the payload. 

13 * Error: `{"error": str, "code": int}` 

14 

15Exit Codes: 

16 * `0`: Success. 

17 * `1`: An unexpected error occurred while accessing the configuration. 

18 * `2`: The specified key was not found in the configuration. 

19""" 

20 

21from __future__ import annotations 

22 

23import platform 

24 

25import typer 

26 

27from bijux_cli.commands.utilities import ( 

28 ascii_safe, 

29 emit_error_and_exit, 

30 new_run_command, 

31 parse_global_flags, 

32) 

33from bijux_cli.contracts import ConfigProtocol 

34from bijux_cli.core.constants import ( 

35 HELP_DEBUG, 

36 HELP_FORMAT, 

37 HELP_NO_PRETTY, 

38 HELP_QUIET, 

39 HELP_VERBOSE, 

40) 

41from bijux_cli.core.di import DIContainer 

42from bijux_cli.core.exceptions import CommandError 

43 

44 

45def get_config( 

46 ctx: typer.Context, 

47 key: str = typer.Argument(..., help="Configuration key to look up"), 

48 quiet: bool = typer.Option(False, "-q", "--quiet", help=HELP_QUIET), 

49 verbose: bool = typer.Option(False, "-v", "--verbose", help=HELP_VERBOSE), 

50 fmt: str = typer.Option("json", "-f", "--format", help=HELP_FORMAT), 

51 pretty: bool = typer.Option(True, "--pretty/--no-pretty", help=HELP_NO_PRETTY), 

52 debug: bool = typer.Option(False, "-d", "--debug", help=HELP_DEBUG), 

53) -> None: 

54 """Retrieves the value for a given configuration key. 

55 

56 This function fetches the value for the specified key from the configuration 

57 service and uses the `new_run_command` helper to emit it in a structured 

58 payload. It handles errors, such as the key not being found. 

59 

60 Args: 

61 ctx (typer.Context): The Typer context for the CLI. 

62 key (str): The configuration key whose value should be retrieved. 

63 quiet (bool): If True, suppresses all output except for errors. 

64 verbose (bool): If True, includes Python/platform details in the output. 

65 fmt (str): The output format, "json" or "yaml". 

66 pretty (bool): If True, pretty-prints the output. 

67 debug (bool): If True, enables debug diagnostics. 

68 

69 Returns: 

70 None: 

71 

72 Raises: 

73 SystemExit: Always exits with a contract-compliant status code and 

74 payload, indicating success or detailing the error. 

75 """ 

76 flags = parse_global_flags() 

77 

78 quiet = flags["quiet"] 

79 verbose = flags["verbose"] 

80 fmt = flags["format"] 

81 pretty = flags["pretty"] 

82 debug = flags["debug"] 

83 

84 include_runtime = verbose 

85 fmt_lower = fmt.lower() 

86 

87 command = "config get" 

88 

89 config_svc = DIContainer.current().resolve(ConfigProtocol) 

90 

91 try: 

92 value = config_svc.get(key) 

93 except CommandError as exc: 

94 if str(exc).startswith("Config key not found"): 

95 emit_error_and_exit( 

96 f"Config key not found: {key}", 

97 code=2, 

98 failure="not_found", 

99 command=command, 

100 fmt=fmt_lower, 

101 quiet=quiet, 

102 include_runtime=include_runtime, 

103 debug=debug, 

104 extra={"key": key}, 

105 ) 

106 emit_error_and_exit( 

107 f"Failed to get config: {exc}", 

108 code=1, 

109 failure="get_failed", 

110 command=command, 

111 fmt=fmt_lower, 

112 quiet=quiet, 

113 include_runtime=include_runtime, 

114 debug=debug, 

115 ) 

116 

117 def payload_builder(include_runtime: bool) -> dict[str, object]: 

118 """Builds a payload containing the retrieved configuration value. 

119 

120 Args: 

121 include_runtime (bool): If True, includes Python and platform info. 

122 

123 Returns: 

124 dict[str, object]: A dictionary containing the key's value and 

125 optional runtime metadata. 

126 """ 

127 payload: dict[str, object] = {"value": value} 

128 if include_runtime: 

129 payload["python"] = ascii_safe(platform.python_version(), "python_version") 

130 payload["platform"] = ascii_safe(platform.platform(), "platform") 

131 return payload 

132 

133 new_run_command( 

134 command_name=command, 

135 payload_builder=payload_builder, 

136 quiet=quiet, 

137 verbose=verbose, 

138 fmt=fmt_lower, 

139 pretty=pretty, 

140 debug=debug, 

141 )