_exceptions.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
  2. from __future__ import annotations
  3. from typing import TYPE_CHECKING, Any, Optional, cast
  4. from typing_extensions import Literal
  5. import httpx
  6. from ._utils import is_dict
  7. from ._models import construct_type
  8. if TYPE_CHECKING:
  9. from .types.chat import ChatCompletion
  10. __all__ = [
  11. "BadRequestError",
  12. "AuthenticationError",
  13. "PermissionDeniedError",
  14. "NotFoundError",
  15. "ConflictError",
  16. "UnprocessableEntityError",
  17. "RateLimitError",
  18. "InternalServerError",
  19. "LengthFinishReasonError",
  20. "ContentFilterFinishReasonError",
  21. "InvalidWebhookSignatureError",
  22. ]
  23. class OpenAIError(Exception):
  24. pass
  25. class APIError(OpenAIError):
  26. message: str
  27. request: httpx.Request
  28. body: object | None
  29. """The API response body.
  30. If the API responded with a valid JSON structure then this property will be the
  31. decoded result.
  32. If it isn't a valid JSON structure then this will be the raw response.
  33. If there was no response associated with this error then it will be `None`.
  34. """
  35. code: Optional[str] = None
  36. param: Optional[str] = None
  37. type: Optional[str]
  38. def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None:
  39. super().__init__(message)
  40. self.request = request
  41. self.message = message
  42. self.body = body
  43. if is_dict(body):
  44. self.code = cast(Any, construct_type(type_=Optional[str], value=body.get("code")))
  45. self.param = cast(Any, construct_type(type_=Optional[str], value=body.get("param")))
  46. self.type = cast(Any, construct_type(type_=str, value=body.get("type")))
  47. else:
  48. self.code = None
  49. self.param = None
  50. self.type = None
  51. class APIResponseValidationError(APIError):
  52. response: httpx.Response
  53. status_code: int
  54. def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None:
  55. super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body)
  56. self.response = response
  57. self.status_code = response.status_code
  58. class APIStatusError(APIError):
  59. """Raised when an API response has a status code of 4xx or 5xx."""
  60. response: httpx.Response
  61. status_code: int
  62. request_id: str | None
  63. def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None:
  64. super().__init__(message, response.request, body=body)
  65. self.response = response
  66. self.status_code = response.status_code
  67. self.request_id = response.headers.get("x-request-id")
  68. class APIConnectionError(APIError):
  69. def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None:
  70. super().__init__(message, request, body=None)
  71. class APITimeoutError(APIConnectionError):
  72. def __init__(self, request: httpx.Request) -> None:
  73. super().__init__(message="Request timed out.", request=request)
  74. class BadRequestError(APIStatusError):
  75. status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride]
  76. class AuthenticationError(APIStatusError):
  77. status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride]
  78. class PermissionDeniedError(APIStatusError):
  79. status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride]
  80. class NotFoundError(APIStatusError):
  81. status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride]
  82. class ConflictError(APIStatusError):
  83. status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride]
  84. class UnprocessableEntityError(APIStatusError):
  85. status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride]
  86. class RateLimitError(APIStatusError):
  87. status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride]
  88. class InternalServerError(APIStatusError):
  89. pass
  90. class LengthFinishReasonError(OpenAIError):
  91. completion: ChatCompletion
  92. """The completion that caused this error.
  93. Note: this will *not* be a complete `ChatCompletion` object when streaming as `usage`
  94. will not be included.
  95. """
  96. def __init__(self, *, completion: ChatCompletion) -> None:
  97. msg = "Could not parse response content as the length limit was reached"
  98. if completion.usage:
  99. msg += f" - {completion.usage}"
  100. super().__init__(msg)
  101. self.completion = completion
  102. class ContentFilterFinishReasonError(OpenAIError):
  103. def __init__(self) -> None:
  104. super().__init__(
  105. f"Could not parse response content as the request was rejected by the content filter",
  106. )
  107. class InvalidWebhookSignatureError(ValueError):
  108. """Raised when a webhook signature is invalid, meaning the computed signature does not match the expected signature."""