diff options
| -rw-r--r-- | docs/api/renderers.rst | 2 | ||||
| -rw-r--r-- | docs/narr/renderers.rst | 7 | ||||
| -rw-r--r-- | pyramid/renderers.py | 21 | ||||
| -rw-r--r-- | pyramid/tests/test_renderers.py | 12 |
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 |
