run and job_request take intent, verdict and repair, and Job.verdict reads the verdict the receipt seals. verdict() gives a job's verdict, its own or one worked out here for another intent (marked not sealed); repair() makes the mechanical fixes on the flagged lines and refuses a proposal that changes another line. EngineError's code reads the job layer's codes as well as the reader's. The getting-started notebook's stored refusal carries its J011. Co-Authored-By: Claude Opus 5.5 <[email protected]>
56 lines
2 KiB
Python
56 lines
2 KiB
Python
"""What the package raises: the engine's refusals and the service's."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import Any, Optional
|
|
|
|
__all__ = ["EngineError", "ServiceError"]
|
|
|
|
_LINE = re.compile(r"^line (\d+):")
|
|
_CODE = re.compile(r"\[([QJ]\d{3})\]$")
|
|
|
|
|
|
class EngineError(Exception):
|
|
"""The engine refused a request, a program or a value, and said why.
|
|
|
|
``message`` is the engine's message as it gave it, the same text the
|
|
command line, the service and the Studio show. ``line`` is the program's
|
|
line the message names, when it names one. ``code`` is the stable code
|
|
the refusal ends with: the reader's (``"Q103"``), or the job layer's
|
|
(``"J011"``: the request, the method, an intent, a repair); code that
|
|
handles errors should test it, not the message.
|
|
"""
|
|
|
|
def __init__(self, message: str, code: Optional[str] = None, line: Optional[int] = None) -> None:
|
|
super().__init__(message)
|
|
self.message = message
|
|
if code is None:
|
|
m = _CODE.search(message)
|
|
code = m.group(1) if m else None
|
|
self.code = code
|
|
if line is None:
|
|
m = _LINE.match(message)
|
|
line = int(m.group(1)) if m else None
|
|
self.line = line
|
|
|
|
def __reduce__(self):
|
|
return (type(self), (self.message, self.code, self.line))
|
|
|
|
|
|
class ServiceError(Exception):
|
|
"""The job service refused a request, a job failed or was cancelled, or
|
|
the service could not be reached.
|
|
|
|
``status`` is the HTTP status (``None`` when no answer came), ``message``
|
|
the service's own words, and ``body`` its whole answer when it sent one.
|
|
"""
|
|
|
|
def __init__(self, message: str, status: Optional[int] = None, body: Any = None) -> None:
|
|
super().__init__(message if status is None else f"{message} (HTTP {status})")
|
|
self.message = message
|
|
self.status = status
|
|
self.body = body
|
|
|
|
def __reduce__(self):
|
|
return (type(self), (self.message, self.status, self.body))
|