summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/api/renderers.rst2
-rw-r--r--docs/narr/renderers.rst7
-rw-r--r--pyramid/renderers.py21
-rw-r--r--pyramid/tests/test_renderers.py12
4 files changed, 42 insertions, 0 deletions
diff --git a/docs/api/renderers.rst b/docs/api/renderers.rst
index ea000ad02..ab182365e 100644
--- a/docs/api/renderers.rst
+++ b/docs/api/renderers.rst
@@ -15,6 +15,8 @@
.. autoclass:: JSONP
+.. autoclass:: ObjectJSONEncoder
+
.. attribute:: null_renderer
An object that can be used in advanced integration cases as input to the
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index 47182c09e..52e97d091 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -212,6 +212,13 @@ to :func:`json.dumps` by overriding the default renderer. See
:class:`pyramid.renderers.JSON` and
:ref:`_adding_and_overriding_renderers` for more information.
+Custom objects can be easily serialized by defining a :func:`__json__` method
+on the object. This method should return values serializable by
+:func:`json_dumps`. By defining this method and using a :term:`JSON`
+renderer the :class:`pyramid.renderers.ObjectJSONEncoder` class will be used
+for encoding your object. If you later define your own custom encoder it will
+override :class:`pyramid.renderers.ObjectJSONEncoder`.
+
You can configure a view to use the JSON renderer by naming ``json`` as the
``renderer`` argument of a view configuration, e.g. by using
:meth:`~pyramid.config.Configurator.add_view`:
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index 401d1fdd4..859fd3953 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -157,6 +157,25 @@ def string_renderer_factory(info):
return value
return _render
+class ObjectJSONEncoder(json.JSONEncoder):
+ """ Encoder that is used by :class:`pyramid.renderers.JSON` and
+ :class:`pyramid.renderers.JSONP`.
+
+ This encoder will look for a :meth:`__json__` method on an object
+ and use the return value when encoding the object to json
+ using :meth:`json_dumps`.
+
+ This class will be used only when you set a JSON or JSONP
+ renderer and you do not define your own custom encoder class.
+
+ .. note:: This feature is new in Pyramid 1.3.
+ """
+
+ def default(self, obj):
+ if hasattr(obj, '__json__') and callable(obj.__json__):
+ return obj.__json__()
+ return json.JSONEncoder.default(self, obj)
+
class JSON(object):
""" Renderer that returns a JSON-encoded string.
@@ -213,6 +232,8 @@ class JSON(object):
""" Convert a Python object to a JSON string.
By default, this uses the :func:`json.dumps` from the stdlib."""
+ if not self.kw.get('cls'):
+ self.kw['cls'] = ObjectJSONEncoder
return json.dumps(value, **self.kw)
json_renderer_factory = JSON() # bw compat
diff --git a/pyramid/tests/test_renderers.py b/pyramid/tests/test_renderers.py
index c2450b875..9d9e608f1 100644
--- a/pyramid/tests/test_renderers.py
+++ b/pyramid/tests/test_renderers.py
@@ -382,6 +382,18 @@ class TestJSON(unittest.TestCase):
result = renderer({'a':now}, {})
self.assertEqual(result, '{"a": "%s"}' % now.isoformat())
+ def test_with_object_encoder(self):
+ class MyObject(object):
+ def __init__(self, x):
+ self.x = x
+ def __json__(self):
+ return {'x': self.x}
+
+ objects = [MyObject(1), MyObject(2)]
+ renderer = self._makeOne()(None)
+ result = renderer(objects, {})
+ self.assertEqual(result, '[{"x": 1}, {"x": 2}]')
+
class Test_string_renderer_factory(unittest.TestCase):
def _callFUT(self, name):
from pyramid.renderers import string_renderer_factory