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

54 statements  

« prev     ^ index     » next       coverage.py v7.13.2, created at 2026-01-26 17:59 +0000

1# SPDX-License-Identifier: Apache-2.0 

2# Copyright © 2025 Bijan Mousavi 

3 

4"""Pure help command logic (intent + payload builders). 

5 

6This module contains no IO, exit behavior, or policy resolution. It exposes 

7pure helpers used by the help command runtime. 

8""" 

9 

10from __future__ import annotations 

11 

12from dataclasses import dataclass 

13import platform as _platform 

14import sys 

15import time 

16 

17import click 

18import typer 

19 

20from bijux_cli.cli.core.command import ascii_safe, normalize_format 

21from bijux_cli.core.enums import LogLevel, OutputFormat 

22from bijux_cli.core.precedence import EffectiveConfig, OutputConfig 

23 

24_HUMAN = "human" 

25_VALID_FORMATS = ("human", "json", "yaml") 

26 

27 

28@dataclass(frozen=True) 

29class HelpIntent: 

30 """Resolved intent for the help command.""" 

31 

32 tokens: list[str] 

33 fmt_lower: str 

34 format_value: OutputFormat | None 

35 error_fmt: OutputFormat 

36 include_runtime: bool 

37 pretty: bool 

38 quiet: bool 

39 log_level: LogLevel 

40 

41 

42def _build_help_intent( 

43 tokens: list[str], 

44 fmt: str, 

45 effective: EffectiveConfig, 

46 output: OutputConfig, 

47) -> HelpIntent: 

48 """Build a normalized help intent from raw CLI inputs.""" 

49 fmt_lower = fmt.strip().lower() 

50 format_value = normalize_format(fmt) 

51 error_fmt = format_value or OutputFormat.JSON 

52 return HelpIntent( 

53 tokens=tokens, 

54 fmt_lower=fmt_lower, 

55 format_value=format_value, 

56 error_fmt=error_fmt, 

57 include_runtime=output.include_runtime, 

58 pretty=output.pretty, 

59 quiet=effective.flags.quiet, 

60 log_level=output.log_level, 

61 ) 

62 

63 

64def _find_target_command( 

65 ctx: typer.Context, path: list[str] 

66) -> tuple[click.Command, click.Context] | None: 

67 """Locate the Click command and context for a given command path.""" 

68 root_cmd: click.Command | None = ctx.parent.command if ctx.parent else None 

69 if not root_cmd: 

70 return None 

71 

72 current_cmd: click.Command | None = root_cmd 

73 current_ctx = click.Context(root_cmd, info_name="bijux") 

74 

75 for token in path: 

76 if not isinstance(current_cmd, click.Group): 

77 return None 

78 next_cmd = current_cmd.get_command(current_ctx, token) 

79 if not next_cmd: 

80 return None 

81 current_ctx = click.Context(next_cmd, info_name=token, parent=current_ctx) 

82 current_cmd = next_cmd 

83 

84 assert current_cmd is not None # noqa: S101 # nosec: B101 

85 return current_cmd, current_ctx 

86 

87 

88def _get_formatted_help(cmd: click.Command, ctx: click.Context) -> str: 

89 """Return formatted help text for a command.""" 

90 help_text = cmd.get_help(ctx) 

91 if ( 

92 hasattr(cmd, "context_settings") 

93 and cmd.context_settings 

94 and "-h" in cmd.context_settings.get("help_option_names", []) 

95 and "-h, --help" not in help_text 

96 ): 

97 help_text = help_text.replace("--help", "-h, --help") 

98 return help_text 

99 

100 

101def _build_help_payload( 

102 help_text: str, include_runtime: bool, started_at: float 

103) -> dict[str, object]: 

104 """Build a structured help payload for JSON/YAML output.""" 

105 payload: dict[str, object] = {"help": help_text} 

106 if include_runtime: 

107 return { 

108 "help": payload["help"], 

109 "python": ascii_safe(sys.version.split()[0], "python_version"), 

110 "platform": ascii_safe(_platform.platform(), "platform"), 

111 "runtime_ms": int((time.perf_counter() - started_at) * 1_000), 

112 } 

113 return payload 

114 

115 

116__all__ = [ 

117 "HelpIntent", 

118 "_HUMAN", 

119 "_VALID_FORMATS", 

120 "_build_help_payload", 

121 "_build_help_intent", 

122 "_find_target_command", 

123 "_get_formatted_help", 

124]