|
|
from datetime import datetime |
|
|
from typing import Any, Optional |
|
|
|
|
|
from pydantic import AnyHttpUrl, BaseModel, Extra, Field |
|
|
|
|
|
|
|
|
class ExceptionReturn(BaseModel): |
|
|
url: Optional[AnyHttpUrl] = None |
|
|
time: datetime = Field(default_factory=datetime.now) |
|
|
code: int = Field(ge=400, le=599) |
|
|
detail: str |
|
|
headers: dict[str, str] = {} |
|
|
|
|
|
class Config: |
|
|
extra = Extra.allow |
|
|
|
|
|
|
|
|
class BaseServerException(Exception): |
|
|
code: int = 500 |
|
|
detail: str = "Server Fault" |
|
|
headers: dict[str, Any] = {} |
|
|
|
|
|
def __init__( |
|
|
self, |
|
|
detail: Optional[str] = None, |
|
|
*, |
|
|
code: Optional[int] = None, |
|
|
headers: Optional[dict[str, Any]] = None, |
|
|
**params |
|
|
) -> None: |
|
|
self.data = ExceptionReturn( |
|
|
detail=detail or self.__class__.detail, |
|
|
code=code or self.__class__.code, |
|
|
headers=headers or self.__class__.headers, |
|
|
**params |
|
|
) |
|
|
super().__init__(detail) |
|
|
|
|
|
|
|
|
class BaseHTTPException(BaseServerException): |
|
|
pass |
|
|
|
|
|
|
|
|
class ServerSideException(BaseServerException): |
|
|
code = 500 |
|
|
detail = "Internal Server Error" |
|
|
|
|
|
|
|
|
class UpstreamAPIException(ServerSideException): |
|
|
code = 502 |
|
|
detail = "Upstram API request failed" |
|
|
|
|
|
|
|
|
class UncaughtException(ServerSideException): |
|
|
code = 500 |
|
|
detail = "Uncaught exception raised during processing" |
|
|
exc: Exception |
|
|
|
|
|
@classmethod |
|
|
def with_exception(cls, e: Exception): |
|
|
c = cls(e.__class__.__qualname__) |
|
|
c.exc = e |
|
|
return c |
|
|
|
|
|
|
|
|
class ClientSideException(BaseServerException): |
|
|
code = 400 |
|
|
detail = "Bad Request" |
|
|
|
|
|
|
|
|
class ValidationException(ClientSideException): |
|
|
code = 422 |
|
|
|
|
|
|
|
|
class RateLimitReachedException(ClientSideException): |
|
|
code = 429 |
|
|
detail = "Rate limit reached" |
|
|
|