Coverage for fingerprint_server_sdk/exceptions.py: 58%

102 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-07-14 10:45 +0000

1""" 

2Server API 

3Fingerprint Server API allows you to get, search, and update Events in a server environment. It can be used for data exports, decision-making, and data analysis scenarios. 

4Server API is intended for server-side usage, it's not intended to be used from the client side, whether it's a browser or a mobile device. 

5The API also supports collection of Automation Intelligence for requests to your server in edge, pre-origin, or middleware contexts. 

6 

7The version of the OpenAPI document: 4 

8Contact: support@fingerprint.com 

9Generated by OpenAPI Generator (https://openapi-generator.tech) 

10 

11Do not edit the class manually. 

12""" # noqa: E501 

13 

14from __future__ import annotations 

15 

16import contextlib 

17from typing import TYPE_CHECKING, Any, Optional 

18 

19from typing_extensions import Self 

20 

21if TYPE_CHECKING: 

22 from fingerprint_server_sdk.rest import RESTResponse 

23 

24 

25class OpenApiException(Exception): 

26 """The base exception class for all OpenAPIExceptions""" 

27 

28 

29class ApiTypeError(OpenApiException, TypeError): 

30 def __init__( 

31 self, 

32 msg: str, 

33 path_to_item: Optional[list[Any]] = None, 

34 valid_classes: Optional[tuple[type, ...]] = None, 

35 key_type: Optional[bool] = None, 

36 ) -> None: 

37 """Raises an exception for TypeErrors 

38 

39 Args: 

40 msg (str): the exception message 

41 

42 Keyword Args: 

43 path_to_item (list): a list of keys an indices to get to the 

44 current_item 

45 None if unset 

46 valid_classes (tuple): the primitive classes that current item 

47 should be an instance of 

48 None if unset 

49 key_type (bool): False if our value is a value in a dict 

50 True if it is a key in a dict 

51 False if our item is an item in a list 

52 None if unset 

53 """ 

54 self.path_to_item = path_to_item 

55 self.valid_classes = valid_classes 

56 self.key_type = key_type 

57 full_msg = msg 

58 if path_to_item: 

59 full_msg = f'{msg} at {render_path(path_to_item)}' 

60 super().__init__(full_msg) 

61 

62 

63class ApiValueError(OpenApiException, ValueError): 

64 def __init__(self, msg: str, path_to_item: Optional[list[Any]] = None) -> None: 

65 """ 

66 Args: 

67 msg (str): the exception message 

68 

69 Keyword Args: 

70 path_to_item (list) the path to the exception in the 

71 received_data dict. None if unset 

72 """ 

73 

74 self.path_to_item = path_to_item 

75 full_msg = msg 

76 if path_to_item: 

77 full_msg = f'{msg} at {render_path(path_to_item)}' 

78 super().__init__(full_msg) 

79 

80 

81class ApiAttributeError(OpenApiException, AttributeError): 

82 def __init__(self, msg: str, path_to_item: Optional[list[Any]] = None) -> None: 

83 """ 

84 Raised when an attribute reference or assignment fails. 

85 

86 Args: 

87 msg (str): the exception message 

88 

89 Keyword Args: 

90 path_to_item (None/list) the path to the exception in the 

91 received_data dict 

92 """ 

93 self.path_to_item = path_to_item 

94 full_msg = msg 

95 if path_to_item: 

96 full_msg = f'{msg} at {render_path(path_to_item)}' 

97 super().__init__(full_msg) 

98 

99 

100class ApiKeyError(OpenApiException, KeyError): 

101 def __init__(self, msg: str, path_to_item: Optional[list[Any]] = None) -> None: 

102 """ 

103 Args: 

104 msg (str): the exception message 

105 

106 Keyword Args: 

107 path_to_item (None/list) the path to the exception in the 

108 received_data dict 

109 """ 

110 self.path_to_item = path_to_item 

111 full_msg = msg 

112 if path_to_item: 

113 full_msg = f'{msg} at {render_path(path_to_item)}' 

114 super().__init__(full_msg) 

115 

116 

117class ApiException(OpenApiException): 

118 def __init__( 

119 self, 

120 status: Optional[int] = None, 

121 reason: Optional[str] = None, 

122 http_resp: Optional[RESTResponse] = None, 

123 *, 

124 body: Optional[str] = None, 

125 data: Optional[Any] = None, 

126 ) -> None: 

127 self.status = status 

128 self.reason = reason 

129 self.body = body 

130 self.data = data 

131 self.headers = None 

132 

133 if http_resp: 

134 if self.status is None: 

135 self.status = http_resp.status 

136 if self.reason is None: 

137 self.reason = http_resp.reason 

138 if self.body is None and http_resp.data is not None: 

139 with contextlib.suppress(UnicodeDecodeError): 

140 self.body = http_resp.data.decode('utf-8') 

141 self.headers = http_resp.headers 

142 

143 @classmethod 

144 def from_response( 

145 cls, 

146 *, 

147 http_resp: RESTResponse, 

148 body: Optional[str], 

149 data: Optional[Any], 

150 ) -> Self: 

151 if http_resp.status == 400: 

152 raise BadRequestException(http_resp=http_resp, body=body, data=data) 

153 

154 if http_resp.status == 401: 

155 raise UnauthorizedException(http_resp=http_resp, body=body, data=data) 

156 

157 if http_resp.status == 403: 

158 raise ForbiddenException(http_resp=http_resp, body=body, data=data) 

159 

160 if http_resp.status == 404: 

161 raise NotFoundException(http_resp=http_resp, body=body, data=data) 

162 

163 # Added new conditions for 409 and 422 

164 if http_resp.status == 409: 

165 raise ConflictException(http_resp=http_resp, body=body, data=data) 

166 

167 if http_resp.status == 422: 

168 raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) 

169 

170 if http_resp.status == 429: 

171 raise TooManyRequestsException(http_resp=http_resp, body=body, data=data) 

172 

173 if 500 <= http_resp.status <= 599: 

174 raise ServiceException(http_resp=http_resp, body=body, data=data) 

175 raise ApiException(http_resp=http_resp, body=body, data=data) 

176 

177 def __str__(self) -> str: 

178 """Custom error messages for exception""" 

179 error_message = f'({self.status})\nReason: {self.reason}\n' 

180 if self.headers: 

181 error_message += f'HTTP response headers: {self.headers}\n' 

182 

183 if self.body: 

184 error_message += f'HTTP response body: {self.body}\n' 

185 

186 if self.data: 

187 error_message += f'HTTP response data: {self.data}\n' 

188 

189 return error_message 

190 

191 

192class BadRequestException(ApiException): 

193 pass 

194 

195 

196class NotFoundException(ApiException): 

197 pass 

198 

199 

200class UnauthorizedException(ApiException): 

201 pass 

202 

203 

204class ForbiddenException(ApiException): 

205 pass 

206 

207 

208class ServiceException(ApiException): 

209 pass 

210 

211 

212class ConflictException(ApiException): 

213 """Exception for HTTP 409 Conflict.""" 

214 

215 pass 

216 

217 

218class UnprocessableEntityException(ApiException): 

219 """Exception for HTTP 422 Unprocessable Entity.""" 

220 

221 pass 

222 

223 

224class TooManyRequestsException(ApiException): 

225 """Exception for HTTP 429 Too Many Requests.""" 

226 

227 pass 

228 

229 

230def render_path(path_to_item: list[Any]) -> str: 

231 """Returns a string representation of a path""" 

232 result = '' 

233 for pth in path_to_item: 

234 if isinstance(pth, int): 

235 result += f'[{pth}]' 

236 else: 

237 result += f"['{pth}']" 

238 return result