ForcePilot/backend/package/yuxi/channels/contract/errors/client.py
Kris b88c0ae29e feat(channels): 批量新增多渠道网关限界上下文基础代码与契约
新增完整的 channels 限界上下文模块,包含契约层、领域核心层、应用服务、管道编排、插件体系、基础设施组合根等全层级代码,新增飞书与微信 iLink 渠道插件基础结构,补充各类 DTO、端口协议与领域服务实现。
2026-07-02 03:22:12 +08:00

119 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""客户端错误类型定义。
定义 ``ClientError`` 抽象基类及其 4 个具体子类,表示由调用方引起的错误
4xx 语义):参数校验失败、认证失败、资源不存在、权限不足。
"""
from __future__ import annotations
from typing import Any
from yuxi.channels.contract.errors.base import Error
class ClientError(Error):
"""客户端错误抽象基类。
表示由调用方引起的错误4xx 语义)。子类包括 ``ValidationError`` /
``AuthError`` / ``NotFoundError`` / ``PermissionDeniedError``。
"""
error_code = "CLIENT_ERROR"
class ValidationError(ClientError, ValueError):
"""字段校验失败错误。
同时继承 ValueError 以兼容 Pydantic field_validator。
"""
error_code = "VALIDATION_ERROR"
def __init__(
self,
field: str,
message: str,
*,
trace_id: str | None = None,
) -> None:
super().__init__(message, trace_id=trace_id)
self.field = field
def to_dict(self) -> dict[str, Any]:
data = super().to_dict()
data["field"] = self.field
return data
class AuthError(ClientError):
"""认证失败错误。
调用方身份认证失败时抛出,如 token 无效、签名错误HTTP 401
"""
error_code = "AUTH_ERROR"
def __init__(
self,
reason: str,
*,
trace_id: str | None = None,
) -> None:
super().__init__(f"Authentication failed: {reason}", trace_id=trace_id)
self.reason = reason
def to_dict(self) -> dict[str, Any]:
data = super().to_dict()
data["reason"] = self.reason
return data
class NotFoundError(ClientError):
"""资源不存在错误。
调用方请求的资源不存在时抛出HTTP 404
"""
error_code = "NOT_FOUND"
def __init__(
self,
resource: str,
id: str,
*,
trace_id: str | None = None,
) -> None:
super().__init__(f"{resource} not found: {id}", trace_id=trace_id)
self.resource = resource
self.id = id
def to_dict(self) -> dict[str, Any]:
data = super().to_dict()
data["resource"] = self.resource
data["id"] = self.id
return data
class PermissionDeniedError(ClientError):
"""权限不足错误。
调用方无权限执行请求的操作时抛出HTTP 403。命名为 ``PermissionDeniedError``
以避免与 Python 内置 ``PermissionError`` 冲突。
"""
error_code = "PERMISSION_DENIED"
def __init__(
self,
reason: str,
*,
trace_id: str | None = None,
) -> None:
super().__init__(f"Permission denied: {reason}", trace_id=trace_id)
self.reason = reason
def to_dict(self) -> dict[str, Any]:
data = super().to_dict()
data["reason"] = self.reason
return data