summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2012-04-17 04:59:33 -0400
committerChris McDonough <chrism@plope.com>2012-04-17 04:59:33 -0400
commit18410a6d9d64786f272268db6368981955ff9f10 (patch)
treec7db8d4401e8a0dc8dc023679eb826d47b958f15
parent1f0d9d2193bb9557d4475885776b5679c8dbfa23 (diff)
downloadpyramid-18410a6d9d64786f272268db6368981955ff9f10.tar.gz
pyramid-18410a6d9d64786f272268db6368981955ff9f10.tar.bz2
pyramid-18410a6d9d64786f272268db6368981955ff9f10.zip
default_encode->_default_encode, dumps->_dumps, massage docs
-rw-r--r--docs/narr/renderers.rst27
-rw-r--r--pyramid/renderers.py44
2 files changed, 47 insertions, 24 deletions
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index 50349c409..02063a112 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -177,6 +177,8 @@ using the API of the ``request.response`` attribute. See
.. index::
pair: renderer; JSON
+.. _json_renderer:
+
JSON Renderer
~~~~~~~~~~~~~
@@ -260,17 +262,34 @@ strings, and so forth).
# the JSON value returned by ``objects`` will be:
# [{"x": 1}, {"x": 2}]
-If you don't own the objects being serialized, it's difficult to add a custom
-``__json__`` method to the object. In this case, a callback can be supplied
-to the renderer which is invoked when other options have failed.
+If you aren't the author of the objects being serialized, it won't be
+possible (or at least not reasonable) to add a custom ``__json__`` method to
+to their classes in order to influence serialization. If the object passed
+to the renderer is not a serializable type, and has no ``__json__`` method,
+usually a :exc:`TypeError` will be raised during serialization. You can
+change this behavior by creating a JSON renderer with a "default" function
+which tries to "sniff" at the object, and returns a valid serialization (a
+string) or raises a TypeError if it can't determine what to do with the
+object. A short example follows:
.. code-block:: python
:linenos:
+ from pyramid.renderers import JSON
+
def default(obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
- raise TypeError
+ raise TypeError('%r is not serializable % (obj,))
+
+ json_renderer = JSON(default=default)
+
+ # then during configuration ....
+ config = Configurator()
+ config.add_renderer('json', json_renderer)
+
+See :class:`pyramid.renderers.JSON` and
+:ref:`adding_and_overriding_renderers` for more information.
.. note::
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index 441976ce4..b393a40a6 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -189,14 +189,20 @@ class JSON(object):
no public API for supplying options to the underlying
:func:`json.dumps` without defining a custom renderer.
+ You can pass a ``default`` argument to this class' constructor (which
+ should be a function) to customize what happens when it attempts to
+ serialize types unrecognized by the base ``json`` module. See
+ :ref:`json_serializing_custom_objects` for more information.
"""
def __init__(self, **kw):
- """ Any keyword arguments will be passed to the encoder
- within :meth:`~pyramid.renderers.JSON.dumps`."""
- # we wrap the default with our own
+ """ Any keyword arguments will be passed to the ``json.dumps``
+ function. A notable exception is the keyword argument ``default``,
+ which is wrapped in a function that sniffs for ``__json__``
+ attributes before it is passed along to ``json.dumps``"""
+ # we wrap the default callback with our own to get __json__ attr
+ # sniffing
self._default = kw.pop('default', None)
-
self.kw = kw
def __call__(self, info):
@@ -210,35 +216,29 @@ class JSON(object):
ct = response.content_type
if ct == response.default_content_type:
response.content_type = 'application/json'
- return self.dumps(value)
+ return self._dumps(value)
return _render
- def default_encode(self, obj):
- """ Encode a custom Python object to a JSON string.
-
- This should be used by subclasses that have overridden
- :meth:`~pyramid.renderers.JSON.dumps` in order to encode objects
- that are not otherwise serializable. This should raise a
- ``TypeError`` when an object cannot be serialized."""
+ def _default_encode(self, obj):
if hasattr(obj, '__json__'):
return obj.__json__()
if self._default is not None:
return self._default(obj)
- raise TypeError(repr(obj) + ' is not JSON serializable')
+ raise TypeError('%r is not JSON serializable' % (obj,))
- def dumps(self, obj):
+ def _dumps(self, obj):
""" Encode a Python object to a JSON string.
By default, this uses the :func:`json.dumps` from the stdlib."""
- return json.dumps(obj, default=self.default_encode, **self.kw)
+ return json.dumps(obj, default=self._default_encode, **self.kw)
json_renderer_factory = JSON() # bw compat
class JSONP(JSON):
""" `JSONP <http://en.wikipedia.org/wiki/JSONP>`_ renderer factory helper
which implements a hybrid json/jsonp renderer. JSONP is useful for
- making cross-domain AJAX requests.
+ making cross-domain AJAX requests.
Configure a JSONP renderer using the
:meth:`pyramid.config.Configurator.add_renderer` API at application
@@ -251,9 +251,9 @@ class JSONP(JSON):
config = Configurator()
config.add_renderer('jsonp', JSONP(param_name='callback'))
- The class also accepts arbitrary keyword arguments; all keyword arguments
- except ``param_name`` are passed to the ``json.dumps`` function as
- keyword arguments:
+ The class' constructor also accepts arbitrary keyword arguments. All
+ keyword arguments except ``param_name`` are passed to the ``json.dumps``
+ function as its keyword arguments.
.. code-block:: python
@@ -265,6 +265,10 @@ class JSONP(JSON):
.. note:: The ability of this class to accept a ``**kw`` in its
constructor is new as of Pyramid 1.4.
+ The arguments passed to this class' constructor mean the same thing as
+ the arguments passed to :class:`pyramid.renderers.JSON` (including
+ ``default``).
+
Once this renderer is registered via
:meth:`~pyramid.config.Configurator.add_renderer` as above, you can use
``jsonp`` as the ``renderer=`` parameter to ``@view_config`` or
@@ -303,7 +307,7 @@ class JSONP(JSON):
plain-JSON encoded string with content-type ``application/json``"""
def _render(value, system):
request = system['request']
- val = self.dumps(value)
+ val = self._dumps(value)
callback = request.GET.get(self.param_name)
if callback is None:
ct = 'application/json'