Source code for sdpb_python.errors

"""Exception types."""

from __future__ import annotations

import re

# SDPB's THROW/ASSERT macros (src/sdpb_util/assert.hxx) format every message as
#   in <function>() at <file>:<line>: \n  <message lines>\nStacktrace:\n 0# ...
_LOCATION = re.compile(r"^in (?P<func>\S+) at (?P<file>.+?):(?P<line>\d+): ?$")


[docs] class SDPBError(RuntimeError): """An error raised inside SDPB's C++ code. ``str(error)`` is SDPB's message, with the source location appended in brackets when SDPB reported one; ``details`` keeps the whole text as SDPB produced it, including its stack trace. """ def __init__(self, details: str): self.details = details super().__init__(summarize(details)) def __reduce__(self): # Pickle (e.g. from a SolverPool worker) with the full text, not the summary return (type(self), (self.details,)) @property def location(self) -> str | None: """``file:line (function)`` of the SDPB source that threw, if known.""" header = _header(self.details) return f"{header['file']}:{header['line']} ({header['func']})" if header else None
def _header(details: str) -> re.Match | None: lines = details.strip().splitlines() return _LOCATION.match(lines[0].strip()) if lines else None def summarize(details: str) -> str: """The message part of an SDPB error text, without the stack trace.""" lines = details.strip().splitlines() if not lines: return "SDPB error" body: list[str] = [] for line in lines: if line.strip() == "Stacktrace:": break body.append(line) header = _LOCATION.match(body[0].strip()) if body else None if header is None: return " ".join(line.strip() for line in body if line.strip()) or lines[0] message = " ".join(line.strip() for line in body[1:] if line.strip()) location = f"{header['file']}:{header['line']} ({header['func']})" return f"{message} [{location}]" if message else f"SDPB error at {location}" def wrap_cpp_error(exc: BaseException) -> BaseException: """Translate an exception from the Cython layer into SDPBError.""" if isinstance(exc, (RuntimeError, ValueError)) and not isinstance(exc, SDPBError): return SDPBError(str(exc)) return exc