Coverage for /home/runner/work/bijux-cli/bijux-cli/src/bijux_cli/commands/memory/service.py: 100%
47 statements
« prev ^ index » next coverage.py v7.10.4, created at 2025-08-19 23:36 +0000
« 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
4"""Implements the root callback for the `bijux memory` command group.
6This module defines the default action for the `bijux memory` command. When
7invoked without a subcommand, it provides a summary of the transient,
8in-memory data store, including the number of keys currently set.
10Output Contract:
11 * Success: `{"status": "ok", "count": int|None, "message": str}`
12 * Verbose: Adds `{"python": str, "platform": str}` to the payload.
13 * Error: `{"error": str, "code": int}`
15Exit Codes:
16 * `0`: Success.
17 * `1`: An unexpected error occurred (e.g., service unavailable).
18 * `3`: An ASCII or encoding error was detected in the environment.
19"""
21from __future__ import annotations
23from collections.abc import Mapping
24import contextlib
25import platform
26import sys
28import typer
30from bijux_cli.commands.memory.utils import resolve_memory_service
31from bijux_cli.commands.utilities import (
32 ascii_safe,
33 contains_non_ascii_env,
34 emit_and_exit,
35 emit_error_and_exit,
36 validate_common_flags,
37)
38from bijux_cli.core.constants import (
39 HELP_DEBUG,
40 HELP_FORMAT,
41 HELP_NO_PRETTY,
42 HELP_QUIET,
43 HELP_VERBOSE,
44)
45from bijux_cli.core.enums import OutputFormat
48def _build_payload(
49 include_runtime: bool, keys_count: int | None
50) -> Mapping[str, object]:
51 """Constructs the payload for the memory summary command.
53 Args:
54 include_runtime (bool): If True, includes Python and platform info.
55 keys_count (int | None): The number of keys in the memory store, or
56 None if the count could not be determined.
58 Returns:
59 Mapping[str, object]: A dictionary containing the status, key count,
60 a confirmation message, and optional runtime metadata.
61 """
62 payload: dict[str, object] = {
63 "status": "ok",
64 "count": keys_count,
65 "message": "Memory command executed",
66 }
67 if include_runtime:
68 payload["python"] = ascii_safe(platform.python_version(), "python_version")
69 payload["platform"] = ascii_safe(platform.platform(), "platform")
70 return payload
73def _run_one_shot_mode(
74 *,
75 command: str,
76 fmt: str,
77 output_format: OutputFormat,
78 quiet: bool,
79 verbose: bool,
80 debug: bool,
81 effective_pretty: bool,
82 include_runtime: bool,
83 keys_count: int | None,
84) -> None:
85 """Orchestrates the execution for a single memory summary request.
87 This helper function handles environment validation, payload construction,
88 and final emission for the memory summary.
90 Args:
91 command (str): The command name for telemetry and error context.
92 fmt (str): The output format string (e.g., "json").
93 output_format (OutputFormat): The output format enum for serialization.
94 quiet (bool): If True, suppresses all output except for errors.
95 verbose (bool): If True, includes runtime metadata in the payload.
96 debug (bool): If True, enables debug diagnostics.
97 effective_pretty (bool): If True, pretty-prints the output.
98 include_runtime (bool): If True, includes Python/platform info.
99 keys_count (int | None): The number of keys in the memory store.
101 Returns:
102 None:
104 Raises:
105 SystemExit: Always exits with a contract-compliant status code and
106 payload upon completion or error.
107 """
108 if contains_non_ascii_env():
109 emit_error_and_exit(
110 "Non-ASCII characters in environment variables",
111 code=3,
112 failure="ascii_env",
113 command=command,
114 fmt=fmt,
115 quiet=quiet,
116 include_runtime=include_runtime,
117 )
119 try:
120 payload = _build_payload(include_runtime, keys_count)
121 except ValueError as exc:
122 emit_error_and_exit(
123 str(exc),
124 code=3,
125 failure="ascii",
126 command=command,
127 fmt=fmt,
128 quiet=quiet,
129 include_runtime=include_runtime,
130 )
132 emit_and_exit(
133 payload=payload,
134 fmt=output_format,
135 effective_pretty=effective_pretty,
136 verbose=verbose,
137 debug=debug,
138 quiet=quiet,
139 command=command,
140 exit_code=0,
141 )
144def memory_summary(
145 ctx: typer.Context,
146 quiet: bool,
147 verbose: bool,
148 fmt: str,
149 pretty: bool,
150 debug: bool,
151) -> None:
152 """Handles the logic for the default `bijux memory` command action.
154 This function is called by the main Typer callback when no subcommand is
155 specified. It resolves the memory service, gets the key count, and then
156 executes the one-shot summary.
158 Args:
159 ctx (typer.Context): The Typer context for the CLI.
160 quiet (bool): If True, suppresses all output except for errors.
161 verbose (bool): If True, includes Python/platform details in the output.
162 fmt (str): The output format, "json" or "yaml".
163 pretty (bool): If True, pretty-prints the output.
164 debug (bool): If True, enables debug diagnostics.
166 Returns:
167 None:
169 Raises:
170 SystemExit: Always exits with a contract-compliant status code and
171 payload upon completion or error.
172 """
173 command = "memory"
174 include_runtime = verbose or debug
176 fmt_lower = validate_common_flags(fmt, command, quiet)
178 output_format = OutputFormat.YAML if fmt_lower == "yaml" else OutputFormat.JSON
179 effective_pretty = debug or pretty
181 svc = resolve_memory_service(command, fmt_lower, quiet, include_runtime, debug)
183 keys_count = None
184 with contextlib.suppress(Exception):
185 keys_count = len(svc.keys())
187 _run_one_shot_mode(
188 command=command,
189 fmt=fmt_lower,
190 output_format=output_format,
191 quiet=quiet,
192 verbose=verbose,
193 debug=debug,
194 effective_pretty=effective_pretty,
195 include_runtime=include_runtime,
196 keys_count=keys_count,
197 )
200def memory(
201 ctx: typer.Context,
202 quiet: bool = typer.Option(False, "-q", "--quiet", help=HELP_QUIET),
203 verbose: bool = typer.Option(False, "-v", "--verbose", help=HELP_VERBOSE),
204 fmt: str = typer.Option("json", "-f", "--format", help=HELP_FORMAT),
205 pretty: bool = typer.Option(True, "--pretty/--no-pretty", help=HELP_NO_PRETTY),
206 debug: bool = typer.Option(False, "-d", "--debug", help=HELP_DEBUG),
207) -> None:
208 """Defines the entrypoint for the `bijux memory` command group.
210 This function serves as the main callback. It handles `--help` requests and,
211 if no subcommand is invoked, delegates to the `memory_summary` function to
212 display the default summary view.
214 Args:
215 ctx (typer.Context): The Typer context for the CLI.
216 quiet (bool): If True, suppresses all output except for errors.
217 verbose (bool): If True, includes runtime metadata in the output.
218 fmt (str): The output format, "json" or "yaml".
219 pretty (bool): If True, pretty-prints the output.
220 debug (bool): If True, enables debug diagnostics.
222 Returns:
223 None:
225 Raises:
226 typer.Exit: Exits after displaying help text.
227 """
228 if any(arg in ("-h", "--help") for arg in sys.argv):
229 if ctx.invoked_subcommand:
230 cmd = getattr(ctx.command, "get_command", None)
231 sub_cmd = cmd(ctx, ctx.invoked_subcommand) if callable(cmd) else None
232 if sub_cmd and hasattr(sub_cmd, "get_help"):
233 typer.echo(
234 sub_cmd.get_help(ctx) # pyright: ignore[reportAttributeAccessIssue]
235 )
236 else:
237 typer.echo(ctx.get_help())
238 else:
239 typer.echo(ctx.get_help())
240 raise typer.Exit()
241 if ctx.invoked_subcommand is None:
242 memory_summary(ctx, quiet, verbose, fmt, pretty, debug)