Coverage for /Users/davegaeddert/Development/dropseed/plain/plain/plain/exceptions.py: 70%

1"""

2 Global Plain exception and warning classes.

3"""

4 import operator

5

6 from plain.utils.hashable import make_hashable

7

8

9 class FieldDoesNotExist(Exception):

10 """The requested model field does not exist"""

11

12 pass

13

14

15 class PackageRegistryNotReady(Exception):

16 """The plain.packages registry is not populated yet"""

17

18 pass

19

20

21 class ObjectDoesNotExist(Exception):

22 """The requested object does not exist"""

23

24 silent_variable_failure = True

25

26

27 class MultipleObjectsReturned(Exception):

28 """The query returned multiple objects when only one was expected."""

29

30 pass

31

32

33 class SuspiciousOperation(Exception):

34 """The user did something suspicious"""

35

36

37 class SuspiciousMultipartForm(SuspiciousOperation):

38 """Suspect MIME request in multipart form data"""

39

40 pass

41

42

43 class SuspiciousFileOperation(SuspiciousOperation):

44 """A Suspicious filesystem operation was attempted"""

45

46 pass

47

48

49 class DisallowedHost(SuspiciousOperation):

50 """HTTP_HOST header contains invalid value"""

51

52 pass

53

54

55 class DisallowedRedirect(SuspiciousOperation):

56 """Redirect to scheme not in allowed list"""

57

58 pass

59

60

61 class TooManyFieldsSent(SuspiciousOperation):

62 """

63 The number of fields in a GET or POST request exceeded

64 settings.DATA_UPLOAD_MAX_NUMBER_FIELDS.

65 """

66

67 pass

68

69

70 class TooManyFilesSent(SuspiciousOperation):

71 """

72 The number of fields in a GET or POST request exceeded

73 settings.DATA_UPLOAD_MAX_NUMBER_FILES.

74 """

75

76 pass

77

78

79 class RequestDataTooBig(SuspiciousOperation):

80 """

81 The size of the request (excluding any file uploads) exceeded

82 settings.DATA_UPLOAD_MAX_MEMORY_SIZE.

83 """

84

85 pass

86

87

88 class RequestAborted(Exception):

89 """The request was closed before it was completed, or timed out."""

90

91 pass

92

93

94 class BadRequest(Exception):

95 """The request is malformed and cannot be processed."""

96

97 pass

98

99

100 class PermissionDenied(Exception):

101 """The user did not have permission to do that"""

102

103 pass

104

105

106 class ViewDoesNotExist(Exception):

107 """The requested view does not exist"""

108

109 pass

110

111

112 class ImproperlyConfigured(Exception):

113 """Plain is somehow improperly configured"""

114

115 pass

116

117

118 class FieldError(Exception):

119 """Some kind of problem with a model field."""

120

121 pass

122

123

124 NON_FIELD_ERRORS = "__all__"

125

126

127 class ValidationError(Exception):

128 """An error while validating data."""

129

130 def __init__(self, message, code=None, params=None):

131 """

132 The `message` argument can be a single error, a list of errors, or a

133 dictionary that maps field names to lists of errors. What we define as

134 an "error" can be either a simple string or an instance of

135 ValidationError with its message attribute set, and what we define as

136 list or dictionary can be an actual `list` or `dict` or an instance

137 of ValidationError with its `error_list` or `error_dict` attribute set.

138 """

139 super().__init__(message, code, params)

140

141 if isinstance(message, ValidationError):

142 if hasattr(message, "error_dict"):

143 message = message.error_dict

144 elif not hasattr(message, "message"):

145 message = message.error_list

146 else:

147 message, code, params = message.message, message.code, message.params

148

149 if isinstance(message, dict):

150 self.error_dict = {}

151 for field, messages in message.items():

152 if not isinstance(messages, ValidationError):

153 messages = ValidationError(messages)

154 self.error_dict[field] = messages.error_list

155

156 elif isinstance(message, list):

157 self.error_list = []

158 for message in message:

159 # Normalize plain strings to instances of ValidationError.

160 if not isinstance(message, ValidationError):

161 message = ValidationError(message)

162 if hasattr(message, "error_dict"):

163 self.error_list.extend(sum(message.error_dict.values(), []))

164 else:

165 self.error_list.extend(message.error_list)

166

167 else:

168 self.message = message

169 self.code = code

170 self.params = params

171 self.error_list = [self]

172

173 @property

174 def message_dict(self):

175 # Trigger an AttributeError if this ValidationError

176 # doesn't have an error_dict.

177 getattr(self, "error_dict")

178

179 return dict(self)

180

181 @property

182 def messages(self):

183 if hasattr(self, "error_dict"):

184 return sum(dict(self).values(), [])

185 return list(self)

186

187 def update_error_dict(self, error_dict):

188 if hasattr(self, "error_dict"):

189 for field, error_list in self.error_dict.items():

190 error_dict.setdefault(field, []).extend(error_list)

191 else:

192 error_dict.setdefault(NON_FIELD_ERRORS, []).extend(self.error_list)

193 return error_dict

194

195 def __iter__(self):

196 if hasattr(self, "error_dict"):

197 for field, errors in self.error_dict.items():

198 yield field, list(ValidationError(errors))

199 else:

200 for error in self.error_list:

201 message = error.message

202 if error.params:

203 message %= error.params

204 yield str(message)

205

206 def __str__(self):

207 if hasattr(self, "error_dict"):

208 return repr(dict(self))

209 return repr(list(self))

210

211 def __repr__(self):

212 return "ValidationError(%s)" % self

213

214 def __eq__(self, other):

215 if not isinstance(other, ValidationError):

216 return NotImplemented

217 return hash(self) == hash(other)

218

219 def __hash__(self):

220 if hasattr(self, "message"):

221 return hash(

222 (

223 self.message,

224 self.code,

225 make_hashable(self.params),

226 )

227 )

228 if hasattr(self, "error_dict"):

229 return hash(make_hashable(self.error_dict))

230 return hash(tuple(sorted(self.error_list, key=operator.attrgetter("message"))))

231

232

233 class EmptyResultSet(Exception):

234 """A database query predicate is impossible."""

235

236 pass

237

238

239 class FullResultSet(Exception):

240 """A database query predicate is matches everything."""

241

242 pass