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