errors.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738
  1. """面向用户的错误类型,以及把 HTTP 状态翻译成人话。"""
  2. class WpError(Exception):
  3. """面向用户的错误:main() 捕获后只打印 message,不打印堆栈。"""
  4. class ApiError(WpError):
  5. def __init__(self, status, message, url=None, body=None):
  6. self.status = status
  7. self.url = url
  8. self.body = body
  9. super().__init__(message)
  10. def explain_api_error(exc, what):
  11. """把 HTTP 状态翻译成对操作者有意义的话(见 references/api.md 的错误约定)。"""
  12. if exc.status == 401:
  13. return WpError(
  14. f"{what}:401 凭据失效或已被撤销。\n"
  15. " · 用户 token 失效 → 重新登录:wikipali-login\n"
  16. " · 模型 token 失效或被撤销 → 重跑:wikipali ensure-model\n"
  17. " 不要自动重试。"
  18. )
  19. if exc.status == 403:
  20. return WpError(f"{what}:403 无权限(不是 channel 的 owner/协作者,或不是模型 owner 本人)。")
  21. if exc.status == 404:
  22. return WpError(
  23. f"{what}:404。三种可能,别只当成「资源不存在」:\n"
  24. " 1. 该端点尚未部署到当前站点——各站代码版本不同,用 wikipali endpoint 换一个再试;\n"
  25. " 2. **已经在最新版站点上仍 404**,说明它还没部署到任何站点,或本就没有这个端点;\n"
  26. " 3. 才是资源真的不存在。"
  27. )
  28. if exc.status == 409:
  29. return WpError(f"{what}:409 同名记录已存在。")
  30. if exc.status == 422:
  31. return WpError(f"{what}:422 参数校验失败——{exc}")
  32. return WpError(f"{what}:HTTP {exc.status} {exc}")