Parse JSON-RPC commands from CLI argument. Supports three formats: 1. JSON string: '{"method":"ping","params":[]}' 2. JSON array: '[{"method":"ping"},{"method":"getConfig"}]' 3. File path: '@commands.json' or '@/path/to/commands.json' Args: json_rpc_arg: JSON-RPC argume
(json_rpc_arg: str | None)
| 93 | |
| 94 | |
| 95 | def parse_json_rpc_commands(json_rpc_arg: str | None) -> list[dict[str, Any]]: |
| 96 | """Parse JSON-RPC commands from CLI argument. |
| 97 | |
| 98 | Supports three formats: |
| 99 | 1. JSON string: '{"method":"ping","params":[]}' |
| 100 | 2. JSON array: '[{"method":"ping"},{"method":"getConfig"}]' |
| 101 | 3. File path: '@commands.json' or '@/path/to/commands.json' |
| 102 | |
| 103 | Args: |
| 104 | json_rpc_arg: JSON-RPC argument from CLI (None if not provided) |
| 105 | |
| 106 | Returns: |
| 107 | List of JSON-RPC command objects |
| 108 | |
| 109 | Raises: |
| 110 | ValueError: If JSON is invalid or file not found |
| 111 | """ |
| 112 | if not json_rpc_arg: |
| 113 | return [] |
| 114 | |
| 115 | # Check if argument is a file path (starts with @) |
| 116 | if json_rpc_arg.startswith("@"): |
| 117 | file_path = Path(json_rpc_arg[1:]) |
| 118 | if not file_path.exists(): |
| 119 | raise ValueError(f"JSON-RPC file not found: {file_path}") |
| 120 | |
| 121 | try: |
| 122 | with open(file_path, "r", encoding="utf-8") as f: |
| 123 | content = f.read() |
| 124 | except KeyboardInterrupt as ki: |
| 125 | handle_keyboard_interrupt(ki) |
| 126 | raise # Always re-raise KeyboardInterrupt |
| 127 | except Exception as e: |
| 128 | raise ValueError(f"Failed to read JSON-RPC file {file_path}: {e}") |
| 129 | |
| 130 | json_str = content |
| 131 | else: |
| 132 | json_str = json_rpc_arg |
| 133 | |
| 134 | # Parse JSON |
| 135 | try: |
| 136 | parsed = json.loads(json_str) |
| 137 | except json.JSONDecodeError as e: |
| 138 | raise ValueError(f"Invalid JSON in RPC commands: {e}") |
| 139 | |
| 140 | # Normalize to list format |
| 141 | commands: list[dict[str, Any]] |
| 142 | if isinstance(parsed, dict): |
| 143 | # Single command object |
| 144 | commands = [cast(dict[str, Any], parsed)] |
| 145 | elif isinstance(parsed, list): |
| 146 | # Array of commands - cast to proper type since JSON parsing returns Any |
| 147 | commands = cast(list[dict[str, Any]], parsed) |
| 148 | else: |
| 149 | raise ValueError( |
| 150 | f"JSON-RPC commands must be object or array, got {type(parsed).__name__}" |
| 151 | ) |
| 152 |
no test coverage detected