1
1
import six
2
+ import sys
2
3
3
4
from .constants import OK , CREATED , ACCEPTED , NO_CONTENT
4
5
from .exceptions import MethodNotImplemented , Unauthorized
5
- from .utils import json , lookup_data , MoreTypesJSONEncoder
6
+ from .utils import json , lookup_data , MoreTypesJSONEncoder , format_traceback
6
7
7
8
8
9
class Resource (object ):
@@ -192,18 +193,23 @@ def build_error(self, err):
192
193
193
194
:returns: A response object
194
195
"""
195
- data = json . dumps ( {
196
+ data = {
196
197
'error' : six .text_type (err ),
197
- })
198
+ }
199
+
200
+ if self .is_debug ():
201
+ # Add the traceback.
202
+ data ['traceback' ] = format_traceback (sys .exc_info ())
203
+
204
+ body = self .raw_serialize (data )
198
205
status = getattr (err , 'status' , 500 )
199
- return self .build_response (data , status = status )
206
+ return self .build_response (body , status = status )
200
207
201
208
def is_debug (self ):
202
209
"""
203
210
Controls whether or not the resource is in a debug environment.
204
211
205
- If so, exceptions will be reraised instead of returning a serialized
206
- response.
212
+ If so, tracebacks will be added to the serialized response.
207
213
208
214
The default implementation simply returns ``False``, so if you're
209
215
integrating with a new web framework, you'll need to override this
@@ -214,6 +220,21 @@ def is_debug(self):
214
220
"""
215
221
return False
216
222
223
+ def bubble_exceptions (self ):
224
+ """
225
+ Controls whether or not exceptions will be re-raised when encountered.
226
+
227
+ The default implementation returns ``False``, which means errors should
228
+ return a serialized response.
229
+
230
+ If you'd like exceptions to be re-raised, override this method & return
231
+ ``True``.
232
+
233
+ :returns: Whether exceptions should be re-raised or not
234
+ :rtype: boolean
235
+ """
236
+ return False
237
+
217
238
def handle (self , endpoint , * args , ** kwargs ):
218
239
"""
219
240
A convenient dispatching method, this centralized some of the common
@@ -257,14 +278,27 @@ def handle(self, endpoint, *args, **kwargs):
257
278
data = view_method (* args , ** kwargs )
258
279
serialized = self .serialize (method , endpoint , data )
259
280
except Exception as err :
260
- if self .is_debug ():
261
- raise
262
-
263
- return self .build_error (err )
281
+ return self .handle_error (err )
264
282
265
283
status = self .status_map .get (self .http_methods [endpoint ][method ], OK )
266
284
return self .build_response (serialized , status = status )
267
285
286
+ def handle_error (self , err ):
287
+ """
288
+ When an exception is encountered, this generates a serialized error
289
+ message to return the user.
290
+
291
+ :param err: The exception seen. The message is exposed to the user, so
292
+ beware of sensitive data leaking.
293
+ :type err: Exception
294
+
295
+ :returns: A response object
296
+ """
297
+ if self .bubble_exceptions ():
298
+ raise err
299
+
300
+ return self .build_error (err )
301
+
268
302
def raw_deserialize (self , body ):
269
303
"""
270
304
The low-level deserialization.
0 commit comments