github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/clients/python-wrapper/lakefs/exceptions.py (about)

     1  """
     2  Exceptions module
     3  """
     4  import http
     5  import json
     6  from contextlib import contextmanager
     7  from typing import Optional, Callable
     8  
     9  import lakefs_sdk.exceptions
    10  from urllib3 import HTTPResponse
    11  
    12  
    13  class LakeFSException(Exception):
    14      """
    15      Base exception for all SDK exceptions
    16      """
    17  
    18  
    19  class ServerException(LakeFSException):
    20      """
    21      Generic exception when no other exception is applicable
    22      """
    23      status_code: int
    24      reason: str
    25      body: dict
    26  
    27      def __init__(self, status=None, reason=None, body=None):
    28          self.status_code = status
    29          self.reason = reason
    30          if body is not None:
    31              try:  # Try to get message from body
    32                  self.body = json.loads(body)
    33              except json.JSONDecodeError:
    34                  self.body = {}
    35          else:
    36              self.body = {}
    37  
    38      def __str__(self):
    39          return f"code: {self.status_code}, reason: {self.reason}, body: {self.body}"
    40  
    41  
    42  class NotFoundException(ServerException):
    43      """
    44      Resource could not be found on lakeFS server
    45      """
    46  
    47  
    48  class ForbiddenException(ServerException):
    49      """
    50      Operation not permitted
    51      """
    52  
    53  
    54  class NoAuthenticationFound(LakeFSException):
    55      """
    56      Raised when no authentication method could be found on Client instantiation
    57      """
    58  
    59  
    60  class BadRequestException(ServerException):
    61      """
    62      Bad Request
    63      """
    64  
    65  
    66  class NotAuthorizedException(ServerException):
    67      """
    68      User not authorized to perform operation
    69      """
    70  
    71  
    72  class UnsupportedOperationException(ServerException):
    73      """
    74      Operation not supported by lakeFS server or SDK
    75      """
    76  
    77  
    78  class ConflictException(ServerException):
    79      """
    80       Resource / request conflict
    81      """
    82  
    83  
    84  class ObjectNotFoundException(NotFoundException, FileNotFoundError):
    85      """
    86      Raised when the currently used object no longer exist in the lakeFS server
    87      """
    88  
    89  
    90  class ObjectExistsException(ServerException, FileExistsError):
    91      """
    92      Raised when Object('...').create(mode='x') and object exists
    93      """
    94  
    95  
    96  class PermissionException(NotAuthorizedException, PermissionError):
    97      """
    98      Raised by Object.open() and Object.create() for compatibility with python
    99      """
   100  
   101  
   102  class InvalidRangeException(ServerException, OSError):
   103      """
   104      Raised when the reference could not be found in the lakeFS server
   105      """
   106  
   107  
   108  class ImportManagerException(LakeFSException):
   109      """
   110      Import manager exceptions that are not originated from the SDK
   111      """
   112  
   113  
   114  class TransactionException(LakeFSException):
   115      """
   116      Exceptions during the transaction commit logic
   117      """
   118  
   119  
   120  _STATUS_CODE_TO_EXCEPTION = {
   121      http.HTTPStatus.BAD_REQUEST.value: BadRequestException,
   122      http.HTTPStatus.UNAUTHORIZED.value: NotAuthorizedException,
   123      http.HTTPStatus.FORBIDDEN.value: ForbiddenException,
   124      http.HTTPStatus.NOT_FOUND.value: NotFoundException,
   125      http.HTTPStatus.METHOD_NOT_ALLOWED.value: UnsupportedOperationException,
   126      http.HTTPStatus.CONFLICT.value: ConflictException,
   127      http.HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value: InvalidRangeException
   128  }
   129  
   130  
   131  @contextmanager
   132  def api_exception_handler(custom_handler: Optional[Callable[[LakeFSException], LakeFSException]] = None):
   133      """
   134      Contexts which converts lakefs_sdk API exceptions to LakeFS exceptions and handles them.
   135  
   136      :param custom_handler: Optional handler which can be used to provide custom behavior for specific exceptions.
   137          If custom_handler returns an exception, this function will raise the exception at the end of the
   138          custom_handler invocation.
   139      """
   140      try:
   141          yield
   142      except lakefs_sdk.ApiException as e:
   143          lakefs_ex = _STATUS_CODE_TO_EXCEPTION.get(e.status, ServerException)(e.status, e.reason, e.body)
   144          if custom_handler is not None:
   145              lakefs_ex = custom_handler(lakefs_ex)
   146  
   147          if lakefs_ex is not None:
   148              raise lakefs_ex from e
   149  
   150  
   151  def handle_http_error(resp: HTTPResponse) -> None:
   152      """
   153      Handles http response and raises the appropriate lakeFS exception if needed
   154  
   155      :param resp: The response to parse
   156      """
   157      if not http.HTTPStatus.OK <= resp.status < http.HTTPStatus.MULTIPLE_CHOICES:
   158          lakefs_ex = _STATUS_CODE_TO_EXCEPTION.get(resp.status, ServerException)(resp.status, resp.reason, resp.data)
   159          raise lakefs_ex