From 18410a6d9d64786f272268db6368981955ff9f10 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Tue, 17 Apr 2012 04:59:33 -0400 Subject: default_encode->_default_encode, dumps->_dumps, massage docs --- docs/narr/renderers.rst | 27 +++++++++++++++++++++++---- pyramid/renderers.py | 44 ++++++++++++++++++++++++-------------------- 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 `_ 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' -- cgit v1.2.3