Coverage for / home / runner / work / bijux-cli / bijux-cli / src / bijux_cli / cli / core / flags.py: 100%
87 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-01-26 17:59 +0000
« 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
4"""Global CLI flag parsing helpers."""
6from __future__ import annotations
8from dataclasses import dataclass
10from bijux_cli.cli.core.constants import (
11 OPT_COLOR,
12 OPT_FORMAT,
13 OPT_LOG_LEVEL,
14 OPT_QUIET,
15)
16from bijux_cli.core.enums import ColorMode, LogLevel, OutputFormat
17from bijux_cli.core.precedence import FlagError
20@dataclass(frozen=True)
21class Flags:
22 """Parsed global CLI flags without precedence or policy decisions."""
24 quiet: bool | None = None
25 log_level: LogLevel | None = None
26 color: ColorMode | None = None
27 format: OutputFormat | None = None
30def parse_global_flags(argv: list[str]) -> Flags:
31 """Parse global CLI flags into a data-only Flags bundle."""
32 quiet: bool | None = None
33 log_level: LogLevel | None = None
34 color: ColorMode | None = None
35 fmt: OutputFormat | None = None
36 i = 0
37 while i < len(argv):
38 flag = argv[i]
39 if flag in OPT_QUIET:
40 quiet = True
41 i += 1
42 continue
43 if flag in OPT_LOG_LEVEL:
44 try:
45 log_level = LogLevel(argv[i + 1])
46 i += 2
47 except (IndexError, ValueError):
48 i += 1
49 continue
50 if flag in OPT_COLOR:
51 try:
52 color = ColorMode(argv[i + 1])
53 i += 2
54 except (IndexError, ValueError):
55 i += 1
56 continue
57 if flag in OPT_FORMAT:
58 try:
59 fmt = OutputFormat(argv[i + 1])
60 i += 2
61 except (IndexError, ValueError):
62 i += 1
63 continue
64 i += 1
65 return Flags(
66 quiet=quiet,
67 log_level=log_level,
68 color=color,
69 format=fmt,
70 )
73def collect_global_flag_errors(argv: list[str]) -> tuple[FlagError, ...]:
74 """Collect parse-time flag errors without applying precedence or defaults."""
75 errors: list[FlagError] = []
76 i = 0
77 while i < len(argv):
78 flag = argv[i]
79 if flag in OPT_LOG_LEVEL:
80 try:
81 LogLevel(argv[i + 1])
82 i += 2
83 except IndexError:
84 errors.append(
85 FlagError(
86 message="Missing value for --log-level.",
87 failure="missing_argument",
88 flag="--log-level",
89 )
90 )
91 i += 1
92 except ValueError:
93 errors.append(
94 FlagError(
95 message="Invalid log level.",
96 failure="invalid_log_level",
97 flag="--log-level",
98 )
99 )
100 i += 2
101 continue
102 if flag in OPT_COLOR:
103 try:
104 ColorMode(argv[i + 1])
105 i += 2
106 except IndexError:
107 errors.append(
108 FlagError(
109 message="Missing value for --color.",
110 failure="missing_argument",
111 flag="--color",
112 )
113 )
114 i += 1
115 except ValueError:
116 errors.append(
117 FlagError(
118 message="Invalid color mode.",
119 failure="invalid_color",
120 flag="--color",
121 )
122 )
123 i += 2
124 continue
125 if flag in OPT_FORMAT:
126 try:
127 OutputFormat(argv[i + 1])
128 i += 2
129 except IndexError:
130 errors.append(
131 FlagError(
132 message="Missing value for --format.",
133 failure="missing_argument",
134 flag="--format",
135 )
136 )
137 i += 1
138 except ValueError:
139 errors.append(
140 FlagError(
141 message=f"Unsupported format: {argv[i + 1]}",
142 failure="invalid_format",
143 flag="--format",
144 )
145 )
146 i += 2
147 continue
148 i += 1
149 return tuple(errors)
152__all__ = ["Flags", "collect_global_flag_errors", "parse_global_flags"]