Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/connexion/exceptions.py: 55%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

82 statements  

1""" 

2This module defines Exception classes used by Connexion to generate a proper response. 

3""" 

4 

5import typing as t 

6 

7from jsonschema.exceptions import ValidationError 

8from starlette.exceptions import HTTPException 

9 

10from .problem import problem 

11 

12 

13class ConnexionException(Exception): 

14 """Base class for any exception thrown by the Connexion framework.""" 

15 

16 

17class ResolverError(LookupError, ConnexionException): 

18 """Error raised at startup when the resolver cannot find a view function for an endpoint in 

19 your specification, and no ``resolver_error`` is configured.""" 

20 

21 

22class InvalidSpecification(ValidationError, ConnexionException): 

23 """Error raised at startup when the provided specification cannot be validated.""" 

24 

25 

26class MissingMiddleware(ConnexionException): 

27 """Error raised when you're leveraging behavior that depends on a specific middleware, 

28 and that middleware is not part of your middleware stack.""" 

29 

30 

31# HTTP ERRORS 

32 

33 

34class ProblemException(HTTPException, ConnexionException): 

35 """ 

36 This exception holds arguments that are going to be passed to the 

37 `connexion.problem` function to generate a proper response. 

38 """ 

39 

40 def __init__( 

41 self, 

42 *, 

43 status=500, 

44 title=None, 

45 detail=None, 

46 type=None, 

47 instance=None, 

48 headers=None, 

49 ext=None, 

50 ): 

51 self.status = self.status_code = status 

52 self.title = title 

53 self.detail = detail 

54 self.type = type 

55 self.instance = instance 

56 self.headers = headers 

57 self.ext = ext 

58 

59 def to_problem(self): 

60 return problem( 

61 status=self.status, 

62 title=self.title, 

63 detail=self.detail, 

64 type=self.type, 

65 instance=self.instance, 

66 headers=self.headers, 

67 ext=self.ext, 

68 ) 

69 

70 

71# CLIENT ERRORS (4XX) 

72 

73 

74class ClientProblem(ProblemException): 

75 """Base exception for any 4XX error. Returns 400 by default, however 

76 :class:`BadRequestProblem` should be preferred for 400 errors.""" 

77 

78 def __init__( 

79 self, 

80 status: int = 400, 

81 title: t.Optional[str] = None, 

82 *, 

83 detail: t.Optional[str] = None, 

84 ): 

85 super().__init__(status=status, title=title, detail=detail) 

86 

87 

88class BadRequestProblem(ClientProblem): 

89 """Problem class for 400 Bad Request errors.""" 

90 

91 def __init__(self, detail=None): 

92 super().__init__(status=400, title="Bad Request", detail=detail) 

93 

94 

95class ExtraParameterProblem(BadRequestProblem): 

96 """Problem class for 400 Bad Request errors raised when extra query or form parameters are 

97 detected and ``strict_validation`` is enabled.""" 

98 

99 def __init__(self, *, param_type: str, extra_params: t.Iterable[str]): 

100 detail = f"Extra {param_type} parameter(s) {','.join(extra_params)} not in spec" 

101 super().__init__(detail=detail) 

102 

103 

104class TypeValidationError(BadRequestProblem): 

105 """Problem class for 400 Bad Request errors raised when path, query or form parameters with 

106 an incorrect type are detected.""" 

107 

108 def __init__(self, schema_type: str, parameter_type: str, parameter_name: str): 

109 detail = f"Wrong type, expected '{schema_type}' for {parameter_type} parameter '{parameter_name}'" 

110 super().__init__(detail=detail) 

111 

112 

113class Unauthorized(ClientProblem): 

114 """Problem class for 401 Unauthorized errors.""" 

115 

116 description = ( 

117 "The server could not verify that you are authorized to access" 

118 " the URL requested. You either supplied the wrong credentials" 

119 " (e.g. a bad password), or your browser doesn't understand" 

120 " how to supply the credentials required." 

121 ) 

122 

123 def __init__(self, detail: str = description): 

124 super().__init__(401, title="Unauthorized", detail=detail) 

125 

126 

127class OAuthProblem(Unauthorized): 

128 """Problem class for 401 Unauthorized errors raised when there is an issue with the received 

129 OAuth headers.""" 

130 

131 pass 

132 

133 

134class OAuthResponseProblem(OAuthProblem): 

135 """Problem class for 401 Unauthorized errors raised when improper OAuth credentials are 

136 retrieved from your OAuth server.""" 

137 

138 pass 

139 

140 

141class Forbidden(HTTPException): 

142 """Problem class for 403 Unauthorized errors.""" 

143 

144 def __init__(self, detail: t.Optional[str] = None): 

145 if detail is None: 

146 detail = ( 

147 "You don't have the permission to access the requested" 

148 " resource. It is either read-protected or not readable by the" 

149 " server." 

150 ) 

151 super().__init__(403, detail=detail) 

152 

153 

154class OAuthScopeProblem(Forbidden): 

155 """Problem class for 403 Unauthorized errors raised because of OAuth scope validation errors.""" 

156 

157 def __init__(self, token_scopes: list, required_scopes: list) -> None: 

158 self.required_scopes = required_scopes 

159 self.token_scopes = token_scopes 

160 detail = ( 

161 f"Provided token does not have the required scopes. " 

162 f"Provided: {token_scopes}; Required: {required_scopes}" 

163 ) 

164 super().__init__(detail=detail) 

165 

166 

167class UnsupportedMediaTypeProblem(ClientProblem): 

168 """Problem class for 415 Unsupported Media Type errors which are raised when Connexion 

169 receives a request with an unsupported media type header.""" 

170 

171 def __init__(self, detail: t.Optional[str] = None): 

172 super().__init__(status=415, title="Unsupported Media Type", detail=detail) 

173 

174 

175# SERVER ERRORS (5XX) 

176 

177 

178class ServerError(ProblemException): 

179 """Base exception for any 5XX error. Returns 500 by default, however 

180 :class:`InternalServerError` should be preferred for 500 errors.""" 

181 

182 def __init__( 

183 self, 

184 status: int = 500, 

185 title: t.Optional[str] = None, 

186 *, 

187 detail: t.Optional[str] = None, 

188 ): 

189 if title is None: 

190 title = "Internal Server Error" 

191 

192 super().__init__(status=status, title=title, detail=detail) 

193 

194 

195class InternalServerError(ServerError): 

196 """Problem class for 500 Internal Server errors.""" 

197 

198 def __init__(self, detail: t.Optional[str] = None): 

199 if detail is None: 

200 detail = ( 

201 "The server encountered an internal error and was unable to complete your " 

202 "request. Either the server is overloaded or there is an error in the application." 

203 ) 

204 super().__init__(status=500, title="Internal Server Error", detail=detail) 

205 

206 

207class NonConformingResponse(InternalServerError): 

208 """Problem class for 500 Internal Server errors raised because of a returned response not 

209 matching the specification if response validation is enabled.""" 

210 

211 def __init__(self, detail: t.Optional[str] = None): 

212 super().__init__(detail=detail) 

213 

214 

215class NonConformingResponseBody(NonConformingResponse): 

216 """Problem class for 500 Internal Server errors raised because of a returned response body not 

217 matching the specification if response validation is enabled.""" 

218 

219 def __init__(self, detail: t.Optional[str] = None): 

220 if detail is None: 

221 detail = "Response body does not conform to specification" 

222 

223 super().__init__(detail=detail) 

224 

225 

226class NonConformingResponseHeaders(NonConformingResponse): 

227 """Problem class for 500 Internal Server errors raised because of a returned response headers 

228 not matching the specification if response validation is enabled.""" 

229 

230 def __init__(self, detail: t.Optional[str] = None): 

231 if detail is None: 

232 detail = "Response headers do not conform to specification" 

233 

234 super().__init__(detail=detail) 

235 

236 

237class ResolverProblem(ServerError): 

238 """Problem class for 501 Not Implemented errors raised when the resolver cannot find a view 

239 function to handle the incoming request.""" 

240 

241 def __init__(self, status: int = 501, *, detail: t.Optional[str] = None): 

242 super().__init__(status=status, title="Not Implemented", detail=detail)