summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-06-25 23:10:53 +0000
committerGerrit Code Review <review@openstack.org>2014-06-25 23:10:53 +0000
commit7d5b94e2f68aa254d4905e90572aa7dc5e04ab28 (patch)
treec69493c40902d41692f45883c262e40c99c772ea
parent9017d113cdd9cddb53894fbba67227e94755a509 (diff)
parent7df71f31ae70f0d6e4e6c7511f5ba35c2977af5e (diff)
downloadpecan-7d5b94e2f68aa254d4905e90572aa7dc5e04ab28.tar.gz
Merge "Serialize WebOb errors as JSON if the client requests it via an Accept header."
-rw-r--r--pecan/core.py21
-rw-r--r--pecan/tests/test_base.py37
2 files changed, 55 insertions, 3 deletions
diff --git a/pecan/core.py b/pecan/core.py
index 4227d42..a43f3de 100644
--- a/pecan/core.py
+++ b/pecan/core.py
@@ -1,7 +1,7 @@
try:
- from simplejson import loads
-except ImportError: # pragma: no cover
- from json import loads # noqa
+ from simplejson import dumps, loads
+except ImportError: # pragma: no cover
+ from json import dumps, loads # noqa
from itertools import chain
from mimetypes import guess_type, add_type
from os.path import splitext
@@ -597,7 +597,22 @@ class PecanBase(object):
except Exception as e:
# if this is an HTTP Exception, set it as the response
if isinstance(e, exc.HTTPException):
+ # if the client asked for JSON, do our best to provide it
+ best_match = acceptparse.MIMEAccept(
+ getattr(req.accept, 'header_value', '*/*')
+ ).best_match(('text/plain', 'text/html', 'application/json'))
state.response = e
+ if best_match == 'application/json':
+ json_body = dumps({
+ 'code': e.status_int,
+ 'title': e.title,
+ 'description': e.detail
+ })
+ if isinstance(json_body, six.text_type):
+ e.text = json_body
+ else:
+ e.body = json_body
+ state.response.content_type = best_match
environ['pecan.original_exception'] = e
# if this is not an internal redirect, run error hooks
diff --git a/pecan/tests/test_base.py b/pecan/tests/test_base.py
index c6f9024..44a6861 100644
--- a/pecan/tests/test_base.py
+++ b/pecan/tests/test_base.py
@@ -8,6 +8,7 @@ else:
import unittest # pragma: nocover
import webob
+from webob.exc import HTTPNotFound
from webtest import TestApp
import six
from six import b as b_
@@ -760,6 +761,42 @@ class TestControllerArguments(PecanTestCase):
assert r.body == b_('eater: 10, dummy, day=12, month=1')
+class TestDefaultErrorRendering(PecanTestCase):
+
+ def test_plain_error(self):
+ class RootController(object):
+ pass
+
+ app = TestApp(Pecan(RootController()))
+ r = app.get('/', status=404)
+ assert r.status_int == 404
+ assert r.content_type == 'text/plain'
+ assert r.body == b_(HTTPNotFound().plain_body({}))
+
+ def test_html_error(self):
+ class RootController(object):
+ pass
+
+ app = TestApp(Pecan(RootController()))
+ r = app.get('/', headers={'Accept': 'text/html'}, status=404)
+ assert r.status_int == 404
+ assert r.content_type == 'text/html'
+ assert r.body == b_(HTTPNotFound().html_body({}))
+
+ def test_json_error(self):
+ class RootController(object):
+ pass
+
+ app = TestApp(Pecan(RootController()))
+ r = app.get('/', headers={'Accept': 'application/json'}, status=404)
+ assert r.status_int == 404
+ json_resp = json.loads(r.body.decode())
+ assert json_resp['code'] == 404
+ assert json_resp['description'] is None
+ assert json_resp['title'] == 'Not Found'
+ assert r.content_type == 'application/json'
+
+
class TestAbort(PecanTestCase):
def test_abort(self):