1.. _renderers_chapter:
2
3Renderers
4=========
5
6A view callable needn't *always* return a :term:`Response` object.  If a view
7happens to return something which does not implement the Pyramid Response
8interface, :app:`Pyramid` will attempt to use a :term:`renderer` to construct a
9response.  For example:
10
11.. code-block:: python
12   :linenos:
13
14   from pyramid.view import view_config
15
16   @view_config(renderer='json')
17   def hello_world(request):
18       return {'content':'Hello!'}
19
20The above example returns a *dictionary* from the view callable.  A dictionary
21does not implement the Pyramid response interface, so you might believe that
22this example would fail.  However, since a ``renderer`` is associated with the
23view callable through its :term:`view configuration` (in this case, using a
24``renderer`` argument passed to :func:`~pyramid.view.view_config`), if the view
25does *not* return a Response object, the renderer will attempt to convert the
26result of the view to a response on the developer's behalf.
27
28Of course, if no renderer is associated with a view's configuration, returning
29anything except an object which implements the Response interface will result
30in an error.  And, if a renderer *is* used, whatever is returned by the view
31must be compatible with the particular kind of renderer used, or an error may
32occur during view invocation.
33
34One exception exists: it is *always* OK to return a Response object, even when
35a ``renderer`` is configured.  In such cases, the renderer is bypassed
36entirely.
37
38Various types of renderers exist, including serialization renderers and
39renderers which use templating systems.
40
41.. index::
42   single: renderer
43   single: view renderer
44
45.. _views_which_use_a_renderer:
46
47Writing View Callables Which Use a Renderer
48-------------------------------------------
49
50As we've seen, a view callable needn't always return a Response object.
51Instead, it may return an arbitrary Python object, with the expectation that a
52:term:`renderer` will convert that object into a response instance on your
53behalf.  Some renderers use a templating system, while other renderers use
54object serialization techniques.  In practice, renderers obtain application
55data values from Python dictionaries so, in practice, view callables which use
56renderers return Python dictionaries.
57
58View callables can :ref:`explicitly call <example_render_to_response_call>`
59renderers, but typically don't.  Instead view configuration declares the
60renderer used to render a view callable's results.  This is done with the
61``renderer`` attribute.  For example, this call to
62:meth:`~pyramid.config.Configurator.add_view` associates the ``json`` renderer
63with a view callable:
64
65.. code-block:: python
66
67   config.add_view('myproject.views.my_view', renderer='json')
68
69When this configuration is added to an application, the
70``myproject.views.my_view`` view callable will now use a ``json`` renderer,
71which renders view return values to a :term:`JSON` response serialization.
72
73Pyramid defines several :ref:`built_in_renderers`, and additional renderers can
74be added by developers to the system as necessary. See
75:ref:`adding_and_overriding_renderers`.
76
77Views which use a renderer and return a non-Response value can vary non-body
78response attributes (such as headers and the HTTP status code) by attaching a
79property to the ``request.response`` attribute. See
80:ref:`request_response_attr`.
81
82As already mentioned, if the :term:`view callable` associated with a
83:term:`view configuration` returns a Response object (or its instance), any
84renderer associated with the view configuration is ignored, and the response is
85passed back to :app:`Pyramid` unchanged.  For example:
86
87.. code-block:: python
88   :linenos:
89
90   from pyramid.response import Response
91   from pyramid.view import view_config
92
93   @view_config(renderer='json')
94   def view(request):
95       return Response('OK') # json renderer avoided
96
97Likewise for an :term:`HTTP exception` response:
98
99.. code-block:: python
100   :linenos:
101
102   from pyramid.httpexceptions import HTTPFound
103   from pyramid.view import view_config
104
105   @view_config(renderer='json')
106   def view(request):
107       return HTTPFound(location='http://example.com') # json renderer avoided
108
109You can of course also return the ``request.response`` attribute instead to
110avoid rendering:
111
112.. code-block:: python
113   :linenos:
114
115   from pyramid.view import view_config
116
117   @view_config(renderer='json')
118   def view(request):
119       request.response.body = 'OK'
120       return request.response # json renderer avoided
121
122.. index::
123   single: renderers (built-in)
124   single: built-in renderers
125
126.. _built_in_renderers:
127
128Built-in Renderers
129------------------
130
131Several built-in renderers exist in :app:`Pyramid`.  These renderers can be
132used in the ``renderer`` attribute of view configurations.
133
134.. note::
135
136   Bindings for officially supported templating languages can be found at
137   :ref:`available_template_system_bindings`.
138
139.. index::
140   pair: renderer; string
141
142``string``: String Renderer
143~~~~~~~~~~~~~~~~~~~~~~~~~~~
144
145The ``string`` renderer renders a view callable result to a string.  If a view
146callable returns a non-Response object, and the ``string`` renderer is
147associated in that view's configuration, the result will be to run the object
148through the Python ``str`` function to generate a string.  Note that if a
149Unicode object is returned by the view callable, it is not ``str()``-ified.
150
151Here's an example of a view that returns a dictionary.  If the ``string``
152renderer is specified in the configuration for this view, the view will render
153the returned dictionary to the ``str()`` representation of the dictionary:
154
155.. code-block:: python
156   :linenos:
157
158   from pyramid.view import view_config
159
160   @view_config(renderer='string')
161   def hello_world(request):
162       return {'content':'Hello!'}
163
164The body of the response returned by such a view will be a string representing
165the ``str()`` serialization of the return value:
166
167.. code-block:: python
168
169   {'content': 'Hello!'}
170
171Views which use the string renderer can vary non-body response attributes by
172using the API of the ``request.response`` attribute.  See
173:ref:`request_response_attr`.
174
175.. index::
176   pair: renderer; JSON
177
178.. _json_renderer:
179
180JSON Renderer
181~~~~~~~~~~~~~
182
183The ``json`` renderer renders view callable results to :term:`JSON`.  By
184default, it passes the return value through the ``json.dumps`` standard library
185function, and wraps the result in a response object.  It also sets the response
186content-type to ``application/json``.
187
188Here's an example of a view that returns a dictionary.  Since the ``json``
189renderer is specified in the configuration for this view, the view will render
190the returned dictionary to a JSON serialization:
191
192.. code-block:: python
193   :linenos:
194
195   from pyramid.view import view_config
196
197   @view_config(renderer='json')
198   def hello_world(request):
199       return {'content':'Hello!'}
200
201The body of the response returned by such a view will be a string representing
202the JSON serialization of the return value:
203
204.. code-block:: python
205
206   {"content": "Hello!"}
207
208The return value needn't be a dictionary, but the return value must contain
209values serializable by the configured serializer (by default ``json.dumps``).
210
211You can configure a view to use the JSON renderer by naming ``json`` as the
212``renderer`` argument of a view configuration, e.g., by using
213:meth:`~pyramid.config.Configurator.add_view`:
214
215.. code-block:: python
216   :linenos:
217
218   config.add_view('myproject.views.hello_world',
219                   name='hello',
220                   context='myproject.resources.Hello',
221                   renderer='json')
222
223Views which use the JSON renderer can vary non-body response attributes by
224using the API of the ``request.response`` attribute.  See
225:ref:`request_response_attr`.
226
227.. _json_serializing_custom_objects:
228
229Serializing Custom Objects
230++++++++++++++++++++++++++
231
232Some objects are not, by default, JSON-serializable (such as datetimes and
233other arbitrary Python objects).  You can, however, register code that makes
234non-serializable objects serializable in two ways:
235
236- Define a ``__json__`` method on objects in your application.
237
238- For objects you don't "own", you can register a JSON renderer that knows
239  about an *adapter* for that kind of object.
240
241Using a Custom ``__json__`` Method
242**********************************
243
244Custom objects can be made easily JSON-serializable in Pyramid by defining a
245``__json__`` method on the object's class. This method should return values
246natively JSON-serializable (such as ints, lists, dictionaries, strings, and so
247forth).  It should accept a single additional argument, ``request``, which will
248be the active request object at render time.
249
250.. code-block:: python
251   :linenos:
252
253   from pyramid.view import view_config
254
255   class MyObject(object):
256       def __init__(self, x):
257           self.x = x
258
259       def __json__(self, request):
260           return {'x':self.x}
261
262   @view_config(renderer='json')
263   def objects(request):
264       return [MyObject(1), MyObject(2)]
265
266   # the JSON value returned by ``objects`` will be:
267   #    [{"x": 1}, {"x": 2}]
268
269Using the ``add_adapter`` Method of a Custom JSON Renderer
270**********************************************************
271
272If you aren't the author of the objects being serialized, it won't be possible
273(or at least not reasonable) to add a custom ``__json__`` method to their
274classes in order to influence serialization.  If the object passed to the
275renderer is not a serializable type and has no ``__json__`` method, usually a
276:exc:`TypeError` will be raised during serialization.  You can change this
277behavior by creating a custom JSON renderer and adding adapters to handle
278custom types. The renderer will attempt to adapt non-serializable objects using
279the registered adapters. A short example follows:
280
281.. code-block:: python
282   :linenos:
283
284   from pyramid.renderers import JSON
285
286   if __name__ == '__main__':
287       config = Configurator()
288       json_renderer = JSON()
289       def datetime_adapter(obj, request):
290           return obj.isoformat()
291       json_renderer.add_adapter(datetime.datetime, datetime_adapter)
292       config.add_renderer('json', json_renderer)
293
294The ``add_adapter`` method should accept two arguments: the *class* of the
295object that you want this adapter to run for (in the example above,
296``datetime.datetime``), and the adapter itself.
297
298The adapter should be a callable.  It should accept two arguments: the object
299needing to be serialized and ``request``, which will be the current request
300object at render time. The adapter should raise a :exc:`TypeError` if it can't
301determine what  to do with the object.
302
303See :class:`pyramid.renderers.JSON` and :ref:`adding_and_overriding_renderers`
304for more information.
305
306.. versionadded:: 1.4
307   Serializing custom objects.
308
309.. index::
310   pair: renderer; JSONP
311
312.. _jsonp_renderer:
313
314JSONP Renderer
315~~~~~~~~~~~~~~
316
317.. versionadded:: 1.1
318
319:class:`pyramid.renderers.JSONP` is a `JSONP
320<https://en.wikipedia.org/wiki/JSONP>`_ renderer factory helper which implements
321a hybrid JSON/JSONP renderer.  JSONP is useful for making cross-domain AJAX
322requests.
323
324Unlike other renderers, a JSONP renderer needs to be configured at startup time
325"by hand".  Configure a JSONP renderer using the
326:meth:`pyramid.config.Configurator.add_renderer` method:
327
328.. code-block:: python
329
330   from pyramid.config import Configurator
331   from pyramid.renderers import JSONP
332
333   config = Configurator()
334   config.add_renderer('jsonp', JSONP(param_name='callback'))
335
336Once this renderer is registered via
337:meth:`~pyramid.config.Configurator.add_renderer` as above, you can use
338``jsonp`` as the ``renderer=`` parameter to ``@view_config`` or
339:meth:`pyramid.config.Configurator.add_view`:
340
341.. code-block:: python
342
343   from pyramid.view import view_config
344
345   @view_config(renderer='jsonp')
346   def myview(request):
347       return {'greeting':'Hello world'}
348
349When a view is called that uses a JSONP renderer:
350
351- If there is a parameter in the request's HTTP query string (aka
352  ``request.GET``) that matches the ``param_name`` of the registered JSONP
353  renderer (by default, ``callback``), the renderer will return a JSONP
354  response.
355
356- If there is no callback parameter in the request's query string, the renderer
357  will return a "plain" JSON response.
358
359Javscript library AJAX functionality will help you make JSONP requests.
360For example, JQuery has a `getJSON function
361<http://api.jquery.com/jQuery.getJSON/>`_, and has equivalent (but more
362complicated) functionality in its `ajax function
363<http://api.jquery.com/jQuery.ajax/>`_.
364
365For example (JavaScript):
366
367.. code-block:: javascript
368
369   var api_url = 'http://api.geonames.org/timezoneJSON' +
370                 '?lat=38.301733840000004' +
371                 '&lng=-77.45869621' +
372                 '&username=fred' +
373                 '&callback=?';
374   jqhxr = $.getJSON(api_url);
375
376The string ``callback=?`` above in the ``url`` param to the JQuery ``getJSON``
377function indicates to jQuery that the query should be made as a JSONP request;
378the ``callback`` parameter will be automatically filled in for you and used.
379
380The same custom-object serialization scheme defined used for a "normal" JSON
381renderer in :ref:`json_serializing_custom_objects` can be used when passing
382values to a JSONP renderer too.
383
384.. index::
385   single: response headers (from a renderer)
386   single: renderer response headers
387
388.. _request_response_attr:
389
390Varying Attributes of Rendered Responses
391----------------------------------------
392
393Before a response constructed by a :term:`renderer` is returned to
394:app:`Pyramid`, several attributes of the request are examined which have the
395potential to influence response behavior.
396
397View callables that don't directly return a response should use the API of the
398:class:`pyramid.response.Response` attribute, available as ``request.response``
399during their execution, to influence associated response behavior.
400
401For example, if you need to change the response status from within a view
402callable that uses a renderer, assign the ``status`` attribute to the
403``response`` attribute of the request before returning a result:
404
405.. code-block:: python
406   :linenos:
407
408   from pyramid.view import view_config
409
410   @view_config(name='gone', renderer='templates/gone.pt')
411   def myview(request):
412       request.response.status = '404 Not Found'
413       return {'URL':request.URL}
414
415Note that mutations of ``request.response`` in views which return a Response
416object directly will have no effect unless the response object returned *is*
417``request.response``.  For example, the following example calls
418``request.response.set_cookie``, but this call will have no effect because a
419different Response object is returned.
420
421.. code-block:: python
422   :linenos:
423
424   from pyramid.response import Response
425
426   def view(request):
427       request.response.set_cookie('abc', '123') # this has no effect
428       return Response('OK') # because we're returning a different response
429
430If you mutate ``request.response`` and you'd like the mutations to have an
431effect, you must return ``request.response``:
432
433.. code-block:: python
434   :linenos:
435
436   def view(request):
437       request.response.set_cookie('abc', '123')
438       return request.response
439
440For more information on attributes of the request, see the API documentation in
441:ref:`request_module`.  For more information on the API of
442``request.response``, see :attr:`pyramid.request.Request.response`.
443
444.. _adding_and_overriding_renderers:
445
446Adding and Changing Renderers
447-----------------------------
448
449New templating systems and serializers can be associated with :app:`Pyramid`
450renderer names.  To this end, configuration declarations can be made which
451change an existing :term:`renderer factory`, and which add a new renderer
452factory.
453
454Renderers can be registered imperatively using the
455:meth:`pyramid.config.Configurator.add_renderer` API.
456
457For example, to add a renderer which renders views which have a
458``renderer`` attribute that is a path that ends in ``.jinja2``:
459
460.. code-block:: python
461
462   config.add_renderer('.jinja2', 'mypackage.MyJinja2Renderer')
463
464The first argument is the renderer name.  The second argument is a reference
465to an implementation of a :term:`renderer factory` or a :term:`dotted Python
466name` referring to such an object.
467
468.. index::
469   pair: renderer; adding
470
471.. _adding_a_renderer:
472
473Adding a New Renderer
474~~~~~~~~~~~~~~~~~~~~~
475
476You may add a new renderer by creating and registering a :term:`renderer
477factory`.
478
479A renderer factory implementation should conform to the
480:class:`pyramid.interfaces.IRendererFactory` interface. It should be capable of
481creating an object that conforms to the :class:`pyramid.interfaces.IRenderer`
482interface. A typical class that follows this setup is as follows:
483
484.. code-block:: python
485   :linenos:
486
487   class RendererFactory:
488       def __init__(self, info):
489           """ Constructor: info will be an object having the
490           following attributes: name (the renderer name), package
491           (the package that was 'current' at the time the
492           renderer was registered), type (the renderer type
493           name), registry (the current application registry) and
494           settings (the deployment settings dictionary). """
495
496       def __call__(self, value, system):
497           """ Call the renderer implementation with the value
498           and the system value passed in as arguments and return
499           the result (a string or unicode object).  The value is
500           the return value of a view.  The system value is a
501           dictionary containing available system values
502           (e.g., view, context, and request). """
503
504The formal interface definition of the ``info`` object passed to a renderer
505factory constructor is available as :class:`pyramid.interfaces.IRendererInfo`.
506
507There are essentially two different kinds of renderer factories:
508
509- A renderer factory which expects to accept an :term:`asset specification`, or
510  an absolute path, as the ``name`` attribute of the ``info`` object fed to its
511  constructor.  These renderer factories are registered with a ``name`` value
512  that begins with a dot (``.``).  These types of renderer factories usually
513  relate to a file on the filesystem, such as a template.
514
515- A renderer factory which expects to accept a token that does not represent a
516  filesystem path or an asset specification in the ``name`` attribute of the
517  ``info`` object fed to its constructor.  These renderer factories are
518  registered with a ``name`` value that does not begin with a dot.  These
519  renderer factories are typically object serializers.
520
521.. sidebar:: Asset Specifications
522
523   An asset specification is a colon-delimited identifier for an :term:`asset`.
524   The colon separates a Python :term:`package` name from a package subpath.
525   For example, the asset specification ``my.package:static/baz.css``
526   identifies the file named ``baz.css`` in the ``static`` subdirectory of the
527   ``my.package`` Python :term:`package`.
528
529Here's an example of the registration of a simple renderer factory via
530:meth:`~pyramid.config.Configurator.add_renderer`, where ``config`` is an
531instance of :meth:`pyramid.config.Configurator`:
532
533.. code-block:: python
534
535   config.add_renderer(name='amf', factory='my.package.MyAMFRenderer')
536
537Adding the above code to your application startup configuration will
538allow you to use the ``my.package.MyAMFRenderer`` renderer factory
539implementation in view configurations. Your application can use this
540renderer by specifying ``amf`` in the ``renderer`` attribute of a
541:term:`view configuration`:
542
543.. code-block:: python
544   :linenos:
545
546   from pyramid.view import view_config
547
548   @view_config(renderer='amf')
549   def myview(request):
550       return {'Hello':'world'}
551
552At startup time, when a :term:`view configuration` is encountered which has a
553``name`` attribute that does not contain a dot, the full ``name`` value is used
554to construct a renderer from the associated renderer factory.  In this case,
555the view configuration will create an instance of an ``MyAMFRenderer`` for each
556view configuration which includes ``amf`` as its renderer value.  The ``name``
557passed to the ``MyAMFRenderer`` constructor will always be ``amf``.
558
559Here's an example of the registration of a more complicated renderer factory,
560which expects to be passed a filesystem path:
561
562.. code-block:: python
563
564   config.add_renderer(name='.jinja2', factory='my.package.MyJinja2Renderer')
565
566Adding the above code to your application startup will allow you to use the
567``my.package.MyJinja2Renderer`` renderer factory implementation in view
568configurations by referring to any ``renderer`` which *ends in* ``.jinja2`` in
569the ``renderer`` attribute of a :term:`view configuration`:
570
571.. code-block:: python
572   :linenos:
573
574   from pyramid.view import view_config
575
576   @view_config(renderer='templates/mytemplate.jinja2')
577   def myview(request):
578       return {'Hello':'world'}
579
580When a :term:`view configuration` is encountered at startup time which has a
581``name`` attribute that does contain a dot, the value of the name attribute is
582split on its final dot.  The second element of the split is typically the
583filename extension.  This extension is used to look up a renderer factory for
584the configured view.  Then the value of ``renderer`` is passed to the factory
585to create a renderer for the view. In this case, the view configuration will
586create an instance of a ``MyJinja2Renderer`` for each view configuration which
587includes anything ending with ``.jinja2`` in its ``renderer`` value.  The
588``name`` passed to the ``MyJinja2Renderer`` constructor will be the full value
589that was set as ``renderer=`` in the view configuration.
590
591Adding a Default Renderer
592~~~~~~~~~~~~~~~~~~~~~~~~~
593
594To associate a *default* renderer with *all* view configurations (even ones
595which do not possess a ``renderer`` attribute), pass ``None`` as the ``name``
596attribute to the renderer tag:
597
598.. code-block:: python
599
600   config.add_renderer(None, 'mypackage.json_renderer_factory')
601
602.. index::
603   pair: renderer; changing
604
605Changing an Existing Renderer
606~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
607
608Pyramid supports overriding almost every aspect of its setup through its
609:ref:`Conflict Resolution <automatic_conflict_resolution>` mechanism. This
610means that, in most cases, overriding a renderer is as simple as using the
611:meth:`pyramid.config.Configurator.add_renderer` method to redefine the
612template extension. For example, if you would like to override the ``json``
613renderer to specify a new renderer, you could do the following:
614
615.. code-block:: python
616
617   json_renderer = pyramid.renderers.JSON()
618   config.add_renderer('json', json_renderer)
619
620After doing this, any views registered with the ``json`` renderer will use the
621new renderer.
622
623.. index::
624   pair: renderer; overriding at runtime
625
626Overriding a Renderer at Runtime
627--------------------------------
628
629.. warning:: This is an advanced feature, not typically used by "civilians".
630
631In some circumstances, it is necessary to instruct the system to ignore the
632static renderer declaration provided by the developer in view configuration,
633replacing the renderer with another *after a request starts*.  For example, an
634"omnipresent" XML-RPC implementation that detects that the request is from an
635XML-RPC client might override a view configuration statement made by the user
636instructing the view to use a template renderer with one that uses an XML-RPC
637renderer.  This renderer would produce an XML-RPC representation of the data
638returned by an arbitrary view callable.
639
640To use this feature, create a :class:`~pyramid.events.NewRequest`
641:term:`subscriber` which sniffs at the request data and which conditionally
642sets an ``override_renderer`` attribute on the request itself, which in turn is
643the *name* of a registered renderer.  For example:
644
645.. code-block:: python
646   :linenos:
647
648   from pyramid.events import subscriber
649   from pyramid.events import NewRequest
650
651   @subscriber(NewRequest)
652   def set_xmlrpc_params(event):
653       request = event.request
654       if (request.content_type == 'text/xml'
655               and request.method == 'POST'
656               and not 'soapaction' in request.headers
657               and not 'x-pyramid-avoid-xmlrpc' in request.headers):
658           params, method = parse_xmlrpc_request(request)
659           request.xmlrpc_params, request.xmlrpc_method = params, method
660           request.is_xmlrpc = True
661           request.override_renderer = 'xmlrpc'
662           return True
663
664The result of such a subscriber will be to replace any existing static renderer
665configured by the developer with a (notional, nonexistent) XML-RPC renderer, if
666the request appears to come from an XML-RPC client.
667