Commits

Anonymous committed 25272db

adding easily overrideable error_handler method to Resource and test case

  • Participants
  • Parent commits 112311f

Comments (0)

Files changed (2)

piston/resource.py

 
         try:
             result = meth(request, *args, **kwargs)
-        except FormValidationError, e:
-            return self.form_validation_response(e)
-        except TypeError, e:
-            result = rc.BAD_REQUEST
-            hm = HandlerMethod(meth)
-            sig = hm.signature
+        except Exception, e:
+            result = self.error_handler(e, request)
 
-            msg = 'Method signature does not match.\n\n'
-
-            if sig:
-                msg += 'Signature should be: %s' % sig
-            else:
-                msg += 'Resource does not expect any parameters.'
-
-            if self.display_errors:
-                msg += '\n\nException was: %s' % str(e)
-
-            result.content = format_error(msg)
-        except Http404:
-            return rc.NOT_FOUND
-        except HttpStatusCode, e:
-            return e.response
-        except Exception, e:
-            """
-            On errors (like code errors), we'd like to be able to
-            give crash reports to both admins and also the calling
-            user. There's two setting parameters for this:
-
-            Parameters::
-             - `PISTON_EMAIL_ERRORS`: Will send a Django formatted
-               error email to people in `settings.ADMINS`.
-             - `PISTON_DISPLAY_ERRORS`: Will return a simple traceback
-               to the caller, so he can tell you what error they got.
-
-            If `PISTON_DISPLAY_ERRORS` is not enabled, the caller will
-            receive a basic "500 Internal Server Error" message.
-            """
-            exc_type, exc_value, tb = sys.exc_info()
-            rep = ExceptionReporter(request, exc_type, exc_value, tb.tb_next)
-            if self.email_errors:
-                self.email_exception(rep)
-            if self.display_errors:
-                return HttpResponseServerError(
-                    format_error('\n'.join(rep.format_exception())))
-            else:
-                raise
 
         emitter, ct = Emitter.get(em_format)
         fields = handler.fields
 
         message.content_subtype = 'html'
         message.send(fail_silently=True)
+
+
+    def error_handler(self, e, request):
+        """
+        Override this method add handling of errors customized for your 
+        needs
+        """
+        if isinstance(e, FormValidationError):
+            return self.form_validation_response(e)
+
+        elif isinstance(e, TypeError):
+            result = rc.BAD_REQUEST
+            hm = HandlerMethod(meth)
+            sig = hm.signature
+
+            msg = 'Method signature does not match.\n\n'
+
+            if sig:
+                msg += 'Signature should be: %s' % sig
+            else:
+                msg += 'Resource does not expect any parameters.'
+
+            if self.display_errors:
+                msg += '\n\nException was: %s' % str(e)
+
+            result.content = format_error(msg)
+        elif isinstance(e, Http404):
+            return rc.NOT_FOUND
+
+        elif isinstance(e, HttpStatusCode):
+            return e.response
+ 
+        else: 
+            """
+            On errors (like code errors), we'd like to be able to
+            give crash reports to both admins and also the calling
+            user. There's two setting parameters for this:
+
+            Parameters::
+             - `PISTON_EMAIL_ERRORS`: Will send a Django formatted
+               error email to people in `settings.ADMINS`.
+             - `PISTON_DISPLAY_ERRORS`: Will return a simple traceback
+               to the caller, so he can tell you what error they got.
+
+            If `PISTON_DISPLAY_ERRORS` is not enabled, the caller will
+            receive a basic "500 Internal Server Error" message.
+            """
+            exc_type, exc_value, tb = sys.exc_info()
+            rep = ExceptionReporter(request, exc_type, exc_value, tb.tb_next)
+            if self.email_errors:
+                self.email_exception(rep)
+            if self.display_errors:
+                return HttpResponseServerError(
+                    format_error('\n'.join(rep.format_exception())))
+            else:
+                raise
 from django.core import mail
 from django.contrib.auth.models import User
 from django.conf import settings
-from django.http import HttpRequest
+from django.http import HttpRequest, HttpResponse
 from django.utils import simplejson
 
 # Piston imports
          # compare the original data dict with the json response 
          # converted to a dict
          self.assertEquals(response_data, simplejson.loads(response.content))
+
+
+class ErrorHandlerTest(TestCase):
+    def test_customized_error_handler(self):
+        """
+        Throw a custom error from a handler method and catch (and format) it 
+        in an overridden error_handler method on the associated Resource object
+        """
+        class GoAwayError(Exception):
+            def __init__(self, name, reason):
+                self.name = name
+                self.reason = reason
+
+        class MyHandler(BaseHandler):
+            """
+            Handler which raises a custom exception 
+            """
+            def read(self, request):
+                raise GoAwayError('Jerome', 'No one likes you')
+
+        class MyResource(Resource):
+            def error_handler(self, error, request):
+                # if the exeption is our exeption then generate a 
+                # custom response with embedded content that will be 
+                # formatted as json 
+                if isinstance(error, GoAwayError):
+                    response = rc.FORBIDDEN
+                    response.content = dict(error=dict(
+                        name=error.name, 
+                        message="Get out of here and dont come back", 
+                        reason=error.reason
+                    ))    
+
+                    return response
+
+                return super(error_handler, self).error_handler(error, request)
+
+        resource = MyResource(MyHandler)
+
+        request = HttpRequest()
+        request.method = 'GET'
+        response = resource(request, emitter_format='json')
+
+        self.assertEquals(401, response.status_code)
+
+        # verify the content we got back can be converted back to json 
+        # and examine the dictionary keys all exist as expected
+        response_data = simplejson.loads(response.content)
+        self.assertTrue('error' in response_data)
+        self.assertTrue('name' in response_data['error'])
+        self.assertTrue('message' in response_data['error'])
+        self.assertTrue('reason' in response_data['error'])
+