| from __future__ import annotations |
|
|
| from dataclasses import dataclass |
| from typing import Any, Dict |
|
|
|
|
| ERROR_CODE_SUCCESS = 200 |
|
|
| ERROR_CODE_AUTH = 10001 |
| ERROR_CODE_RATE = 10002 |
| ERROR_CODE_RISK = 10003 |
| ERROR_CODE_PARSE = 10004 |
| ERROR_CODE_TIMEOUT = 10005 |
| ERROR_CODE_MISSING_DEPENDENCY = 10006 |
| ERROR_CODE_INVALID_TARGET = 10007 |
| ERROR_CODE_TASK_NOT_FOUND = 10008 |
| ERROR_CODE_TASK_NOT_READY = 10009 |
| ERROR_CODE_ORCHESTRATOR_DB = 10010 |
|
|
|
|
| @dataclass(frozen=True) |
| class ApiErrorSpec: |
| code: int |
| http_status: int |
| default_msg: str |
|
|
|
|
| ERROR_SPECS: Dict[str, ApiErrorSpec] = { |
| "auth": ApiErrorSpec(code=ERROR_CODE_AUTH, http_status=401, default_msg="auth required"), |
| "rate": ApiErrorSpec(code=ERROR_CODE_RATE, http_status=429, default_msg="rate limited"), |
| "risk": ApiErrorSpec(code=ERROR_CODE_RISK, http_status=403, default_msg="risk control"), |
| "parse": ApiErrorSpec(code=ERROR_CODE_PARSE, http_status=500, default_msg="parse error"), |
| "timeout": ApiErrorSpec(code=ERROR_CODE_TIMEOUT, http_status=504, default_msg="timeout"), |
| "missing_dependency": ApiErrorSpec( |
| code=ERROR_CODE_MISSING_DEPENDENCY, |
| http_status=500, |
| default_msg="missing dependency", |
| ), |
| "invalid_target": ApiErrorSpec( |
| code=ERROR_CODE_INVALID_TARGET, |
| http_status=400, |
| default_msg="invalid target", |
| ), |
| "task_not_found": ApiErrorSpec( |
| code=ERROR_CODE_TASK_NOT_FOUND, |
| http_status=404, |
| default_msg="task not found", |
| ), |
| "task_not_ready": ApiErrorSpec( |
| code=ERROR_CODE_TASK_NOT_READY, |
| http_status=409, |
| default_msg="task not ready", |
| ), |
| "orchestrator_db": ApiErrorSpec( |
| code=ERROR_CODE_ORCHESTRATOR_DB, |
| http_status=503, |
| default_msg="orchestrator db unavailable", |
| ), |
| } |
|
|
|
|
| class ApiException(Exception): |
| def __init__(self, kind: str, msg: str | None = None, data: Any = None): |
| self.kind = (kind or "").strip() or "parse" |
| spec = ERROR_SPECS.get(self.kind) or ERROR_SPECS["parse"] |
| self.code = spec.code |
| self.http_status = spec.http_status |
| self.msg = msg if msg is not None and str(msg).strip() != "" else spec.default_msg |
| self.data = data |
| super().__init__(self.msg) |
|
|