Coverage for /home/runner/work/bijux-cli/bijux-cli/src/bijux_cli/commands/memory/set.py: 100%
24 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 `memory set` subcommand for the Bijux CLI.
6This module contains the logic for storing a key-value pair in a transient,
7in-memory data store. The data persists only for the lifetime of the
8application's parent process. A structured confirmation is emitted upon success.
10Output Contract:
11 * Success: `{"status": "updated", "key": str, "value": 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, set failed).
18 * `2`: The provided key was invalid.
19"""
21from __future__ import annotations
23from collections.abc import Mapping
24import platform
26import typer
28from bijux_cli.commands.memory.utils import resolve_memory_service
29from bijux_cli.commands.utilities import (
30 ascii_safe,
31 emit_error_and_exit,
32 new_run_command,
33 validate_common_flags,
34)
35from bijux_cli.core.constants import (
36 HELP_DEBUG,
37 HELP_FORMAT,
38 HELP_NO_PRETTY,
39 HELP_QUIET,
40 HELP_VERBOSE,
41)
44def _build_payload(include_runtime: bool, key: str, value: str) -> Mapping[str, object]:
45 """Constructs the payload confirming a key-value pair was set.
47 Args:
48 include_runtime (bool): If True, includes Python and platform info.
49 key (str): The key that was updated.
50 value (str): The new value assigned to the key.
52 Returns:
53 Mapping[str, object]: A dictionary containing the status, key, value,
54 and optional runtime metadata.
55 """
56 payload: dict[str, object] = {"status": "updated", "key": key, "value": value}
57 if include_runtime:
58 payload["python"] = ascii_safe(platform.python_version(), "python_version")
59 payload["platform"] = ascii_safe(platform.platform(), "platform")
60 return payload
63def set_memory(
64 key: str = typer.Argument(..., help="Key to set"),
65 value: str = typer.Argument(..., help="Value to set"),
66 quiet: bool = typer.Option(False, "-q", "--quiet", help=HELP_QUIET),
67 verbose: bool = typer.Option(False, "-v", "--verbose", help=HELP_VERBOSE),
68 fmt: str = typer.Option("json", "-f", "--format", help=HELP_FORMAT),
69 pretty: bool = typer.Option(True, "--pretty/--no-pretty", help=HELP_NO_PRETTY),
70 debug: bool = typer.Option(False, "-d", "--debug", help=HELP_DEBUG),
71) -> None:
72 """Sets a key-value pair in the transient in-memory store.
74 This command validates the key's format and then stores the key-value
75 pair using the memory service.
77 Args:
78 key (str): The memory key to set. Must be between 1 and 4096 printable,
79 non-whitespace characters.
80 value (str): The value to associate with the key.
81 quiet (bool): If True, suppresses all output except for errors.
82 verbose (bool): If True, includes Python/platform details in the output.
83 fmt (str): The output format, "json" or "yaml".
84 pretty (bool): If True, pretty-prints the output.
85 debug (bool): If True, enables debug diagnostics.
87 Returns:
88 None:
90 Raises:
91 SystemExit: Always exits with a contract-compliant status code and
92 payload, indicating success or detailing an error.
93 """
94 command = "memory set"
96 fmt_lower = validate_common_flags(fmt, command, quiet)
98 if not (
99 1 <= len(key) <= 4096 and all(c.isprintable() and not c.isspace() for c in key)
100 ):
101 emit_error_and_exit(
102 "Invalid key: must be 1-4096 printable non-space characters",
103 code=2,
104 failure="invalid_key",
105 command=command,
106 fmt=fmt_lower,
107 quiet=quiet,
108 include_runtime=verbose,
109 debug=debug,
110 )
112 memory_svc = resolve_memory_service(command, fmt_lower, quiet, verbose, debug)
114 try:
115 memory_svc.set(key, value)
116 except Exception as exc:
117 emit_error_and_exit(
118 f"Failed to set memory: {exc}",
119 code=1,
120 failure="set_failed",
121 command=command,
122 fmt=fmt_lower,
123 quiet=quiet,
124 include_runtime=verbose,
125 debug=debug,
126 )
128 new_run_command(
129 command_name=command,
130 payload_builder=lambda include: _build_payload(include, key, value),
131 quiet=quiet,
132 verbose=verbose,
133 fmt=fmt_lower,
134 pretty=pretty,
135 debug=debug,
136 )