From 0decb747ac9239faf5119b7faa80596995746ef9 Mon Sep 17 00:00:00 2001 From: blasty Date: Fri, 24 Jul 2026 14:41:23 +0200 Subject: refactor: extract shared error hierarchy + Session into idatui/errors.py The IDAError/IDAConnectionError/IDAToolError/... exceptions and the Session dataclass were defined in client.py (the ida-pro-mcp HTTP client), but the idalib worker path (worker_client/domain/app) needs them without the HTTP transport. Move them to a transport-agnostic errors.py; client.py re-exports them so the deprecated mcp tooling and stress tests are unchanged (verified: errors.IDAToolError IS client.IDAToolError, so cross-module `except` still works). worker_client, domain (TYPE_CHECKING-guarded IDAClient hint), app, and __init__ now import the shared types from errors.py. This decouples the worker path from client.py at runtime -- the prerequisite for deleting the mcp transport. --- idatui/errors.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 idatui/errors.py (limited to 'idatui/errors.py') diff --git a/idatui/errors.py b/idatui/errors.py new file mode 100644 index 0000000..29b09ae --- /dev/null +++ b/idatui/errors.py @@ -0,0 +1,76 @@ +"""Transport-agnostic error hierarchy and the Session model. + +These were originally defined in client.py (the ida-pro-mcp HTTP client), but the +idalib worker path (worker_client / domain / app) needs the same exception types +and Session dataclass without dragging in the HTTP transport. They live here so +both backends share one definition; client.py re-exports them for backwards +compatibility with the (deprecated) mcp tooling and the stress tests. +""" +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + + +# --------------------------------------------------------------------------- # +# Exceptions +# --------------------------------------------------------------------------- # +class IDAError(Exception): + """Base class for all client errors.""" + + +class IDAConnectionError(IDAError): + """The transport could not be established or was lost.""" + + +class IDATimeoutError(IDAError): + """A request exceeded its deadline.""" + + +class IDAProtocolError(IDAError): + """Malformed or unexpected HTTP / JSON-RPC framing.""" + + +class IDARPCError(IDAError): + """The JSON-RPC envelope carried an ``error`` object.""" + + def __init__(self, code: int, message: str, data: Any = None): + super().__init__(f"JSON-RPC error {code}: {message}") + self.code = code + self.message = message + self.data = data + + +class IDAToolError(IDAError): + """A tool call returned ``result.isError == true`` (a hard failure).""" + + def __init__(self, tool: str, message: str): + super().__init__(f"tool {tool!r} failed: {message}") + self.tool = tool + self.message = message + + +class IDASessionError(IDAError): + """No IDB session is open, or several are and none was pinned.""" + + +# --------------------------------------------------------------------------- # +# Session model +# --------------------------------------------------------------------------- # +@dataclass(frozen=True) +class Session: + session_id: str + filename: str + input_path: str + is_active: bool = False + is_analyzing: bool = False + + @classmethod + def from_dict(cls, d: dict) -> "Session": + return cls( + session_id=d.get("session_id", ""), + filename=d.get("filename", ""), + input_path=d.get("input_path", ""), + is_active=bool(d.get("is_active", False)), + is_analyzing=bool(d.get("is_analyzing", False)), + ) -- cgit v1.3.1-sl0p