Send batch of commands. Args: commands: List of dicts with "command" and optional "params" timeout: Optional timeout override Returns: List of results (may include errors) on success, or error dict if batch rejected Raises:
(
self, commands: list[dict], timeout: Optional[float] = None
)
| 167 | ) |
| 168 | |
| 169 | def batch( |
| 170 | self, commands: list[dict], timeout: Optional[float] = None |
| 171 | ) -> list[dict] | dict: |
| 172 | """ |
| 173 | Send batch of commands. |
| 174 | |
| 175 | Args: |
| 176 | commands: List of dicts with "command" and optional "params" |
| 177 | timeout: Optional timeout override |
| 178 | |
| 179 | Returns: |
| 180 | List of results (may include errors) on success, or error dict if batch rejected |
| 181 | |
| 182 | Raises: |
| 183 | TimeoutError: If response not received in time |
| 184 | """ |
| 185 | request_id = str(uuid.uuid4()) |
| 186 | |
| 187 | batch_commands = [] |
| 188 | for i, cmd in enumerate(commands): |
| 189 | batch_cmd = { |
| 190 | "id": f"{request_id}-{i}", |
| 191 | "command": cmd["command"], |
| 192 | } |
| 193 | if "params" in cmd: |
| 194 | batch_cmd["params"] = cmd["params"] |
| 195 | batch_commands.append(batch_cmd) |
| 196 | |
| 197 | message = {"type": "batch", "id": request_id, "commands": batch_commands} |
| 198 | |
| 199 | self._send_message(message) |
| 200 | |
| 201 | deadline = time.time() + (timeout or self.timeout) |
| 202 | |
| 203 | while True: |
| 204 | remaining = deadline - time.time() |
| 205 | if remaining <= 0: |
| 206 | raise TimeoutError("Timeout waiting for response") |
| 207 | |
| 208 | response = self._recv_message(remaining) |
| 209 | |
| 210 | if response.get("type") == "response" and response.get("id") == request_id: |
| 211 | # Batch was processed: return individual results even if some failed. |
| 212 | # A "results" key means the batch ran and each entry has its own |
| 213 | # success/failure status (partial failure is normal). |
| 214 | if "results" in response: |
| 215 | return response.get("results", []) |
| 216 | |
| 217 | # No "results" key means the batch was rejected at the protocol |
| 218 | # level before any commands were executed (e.g. empty batch, size |
| 219 | # limit exceeded). |
| 220 | return { |
| 221 | "error": True, |
| 222 | "success": False, |
| 223 | "message": response.get("error", {}).get( |
| 224 | "message", "Batch rejected" |
| 225 | ), |
| 226 | "code": response.get("error", {}).get("code", "UNKNOWN"), |