Edgewall Software

Changes between Version 35 and Version 36 of TracDev/PortingFromGenshiToJinja


Ignore:
Timestamp:
Jan 15, 2017, 1:00:11 AM (7 years ago)
Author:
Christian Boos
Comment:

document IRequestHandler.process_request, remove some 'j's, fix source: links

Legend:

Unmodified
Added
Removed
Modified
  • TracDev/PortingFromGenshiToJinja

    v35 v36  
    33
    44The following documentation corresponds to the [Proposals/Jinja Jinja] development proposal; it will be in Trac 1.3.x if all goes well \\
    5 (Git branch: [log:cboos.git@jinja2] - [https://github.com/cboos/trac.git github mirror]).
     5(Git branch: [log:cboos.git@jinja2] (original) - [log:cboos.git@jinja2-trunk-r15341] (latest) - [https://github.com/cboos/trac.git github mirror]).
    66
    77Track the integration progress in #12639.
     
    1414
    1515For migrating your own templates, a good way to start is to learn from examples.
    16 Compare the 'j...' Jinja templates found in source:cboos.git/trac/templates@jinja2 with their corresponding Genshi ones.
     16Compare the  [source:cboos.git/trac/templates@jinja2-trunk-r15341 Jinja2 trac/templates] with their [source:trunk/trac/templates Genshi counterpart].
    1717
    1818In the first part of this document, we try to cover all the Genshi features used by Trac and present their Jinja2 equivalent. Whenever possible, we tried to minimize these differences by customizing the Jinja2 syntax. For example, we use `${...}` for variable expansion, like Genshi does, instead of `{{...}}`. Another aspect of our usage convention is that we favor [#ifthenelse line statements] over `{% ... %}`. So even someone familiar with the "default" Jinja2 syntax should glance through this document to see how "we" use Jinja2, as summarized in the table below.
     
    2020The last part of the document describes the Python code changes, focusing notably on how to replace the deprecated `ITemplateStreamFilter` interface.
    2121
    22 Note that Genshi will be supported concurrently with Jinja2 only for a short while, including the deprecated `ITemplateStreamFilter` interface, but probably only during the 1.3.x development period, and at most for the 1.4-stable period. If for some reason you're stuck to having to support Genshi templates, you'll have to stick to Trac 1.2.x or 1.3.x. But you really should make the transition effort as Jinja2 templates are 5-10x faster than their Genshi equivalent, for only a 1/5th of the cost in memory usage.
     22Note that Genshi will be supported concurrently with Jinja2 only for a short while, for the 1.3.x development period and for the 1.4-stable period. If for some reason you're stuck to having to support Genshi templates, you'll have to stick to Trac 1.2.x or 1.3.x. But you really should make the transition effort as Jinja2 templates are 5-10x faster than their Genshi equivalent, for only a 1/5th of the cost in memory usage.
     23
    2324
    2425== The Jinja2 syntax
     
    5657|| lstrip_blocks ||  yes  || whitespace removal before a block
    5758|| newstyle_gettext ||  yes  || i.e. like the Trac `gettext`
     59
    5860
    5961== Changes in the HTML
     
    143145      #   set can_append = false
    144146      #   set preview_mode = false
    145       #   include "jticket_box.html"
     147      #   include "ticket_box.html"
    146148      # endwith
    147149   }}}
     
    492494</html>
    493495   }}}
    494  - Jinja [source:cboos.git/trac/templates/jindex.html@jinja2 jindex.html]:
     496 - Jinja [source:cboos.git/trac/templates/index.html@jinja2-trunk-r15341 index.html]:
    495497   {{{#!html+jinja
    496498<!DOCTYPE html>
     
    521523In this small example, there's no common Trac layout used (as the index is a bit special).
    522524For how a "normal" template looks like, see for example
    523 [source:trac/templates/jdiff_form.html@jinja2 jdiff_form.html], another small template.
     525[source:trac/templates/diff_form.html@jinja2-trunk-r15341 diff_form.html], another small template.
    524526
    525527Note that a Jinja2 .html template can usually be rendered directly in the browser, to have a rough taste of how it will look like:
     
    555557Instead of the Genshi way of including a template containing filters, the Jinja2 way follows an "object oriented" approach, with inheritance and overriders. Consider that some named sections (or "blocks") of the base template are similar to "methods", imagine that you only have to "subclass" this base template and "reimplement" the overridable methods with your specific content, and there you have it.
    556558
    557 More specifically, you'll have to "extend" the [source:cboos.git/trac/templates/jlayout.html@jinja2 jlayout.html] template, and redefine the "head", and "content" blocks if needed.
    558 
    559 All the details are available in HtmlTemplates#Jinjaarchitecture, including a walkthrough for the specific example of the [source:cboos.git/trac/search/templates/jsearch.html@jinja2 jsearch.html] template.
    560 
    561 For the jsearch.html example we focus on the //structure// of the templates, the //include// relationship and the decomposition in //blocks//.
    562 
    563 
    564 But we also have a complete conversion [./Example example], which displays the Genshi wiki_view.html template and the Jinja2 jwiki_view.html template side-by-side, along with comments explaining the conversion choices.
     559More specifically, you'll have to "extend" the [source:cboos.git/trac/templates/layout.html@jinja2-trunk-r15341 layout.html] template, and redefine the "head", and "content" blocks if needed.
     560
     561All the details are available in HtmlTemplates#Jinja2architecture, including a walkthrough for the specific example of the [source:cboos.git/trac/search/templates/search.html@jinja2-trunk-r15341 search.html] template.
     562
     563For the search.html example we focus on the //structure// of the templates, the //include// relationship and the decomposition in //blocks//.
     564
     565
     566But we also have a complete conversion [./Example example], which displays the Genshi wiki_view.html template and the Jinja2 wiki_view.html template side-by-side, along with comments explaining the conversion choices.
    565567
    566568=== Tips and tricks
     
    576578at the same time as the template name. This hasn't changed with Jinja2.
    577579
    578 In fact, no changes to the `IRequestHandler` interface were needed.
     580The `IRequestHandler.process_request` method has seen one, important, change: instead of returning a triple of the template, data, and content type, a simple pair of template and data must be returned.
     581
     582If the legacy return convention is used, this means that `'template.html'` is supposed to be a Genshi template:
     583{{{#!py
     584        return 'template.html', data, None
     585}}}
     586(`None` here is interpreted to mean the default content type, i.e. `'text/html'`)
     587
     588The new return convention is simpler, and means that `'template.html'` is now supposed to be a Jinja2 template:
     589{{{#!py
     590        return 'template.html', data
     591}}}
     592
     593If a special content-type must be used, or if other variation on the generation of the content must be specified, this can now be done by passing a `dict`:
     594{{{#!py
     595        return 'template.html', data, {'content_type': 'application/rss+xml'}
     596}}}
     597This has the advantage of supporting a few more keywords (see the API doc), and to be extensible with more metadata at little cost.
     598
     599Note that as long as we have to support the legacy Genshi templates, a `None` value passed as third argument won't be interpreted as an empty `dict`, but rather as an empty `content_type`.
    579600
    580601
     
    589610There were two post-processing steps from which plugin writers did benefit, possibly unknowingly:
    590611 1. the addition of the `__FORM_TOKEN` hidden parameter to <form> elements, necessary for successful POST operations
    591  2. accessibility key enabling/disabling (TODO)
     612 2. accessibility key enabling/disabling
    592613
    593614As this no longer happen, it's now the responsibility of plugin writers to add this <input> in their content. This is simple enough:
     
    598619</form>
    599620}}}
     621
    600622This gets even simpler thanks to a default macro:
    601623{{{#!html+jinja
     
    606628}}}
    607629
    608 The `jmacros` corresponds to the [source:cboos.git/trac/templates/jmacros.html@jinja2 trac/templates/jmacros.html] default macros, and this file is included by default (in `jlayout.html`), so you don't have to bother to include it yourself (as most of the templates will extend `jlayout.html`).
    609 
     630The `jmacros` in the above corresponds to the [source:cboos.git/trac/templates/macros.html@jinja2-trunk-r15341 trac/templates/macros.html] default macros, and this file is included by default (in `layout.html`), so you don't have to bother to include it yourself, as long as your template extends `layout.html`.
     631
     632For the accessibility key, it's also quite simple: instead of hard-coding the key as an `accesskey="e"` attribute, simply use the `accesskey('e')` function call, it will know if it has to produce the attribute or not depending on the current user preferences.
    610633
    611634==== Hooking into the HTML content produced by other templates
     
    615638So this means this specific step of the migration, perhaps the less straightforward, will be of interest for most plugin developers.
    616639
    617 Note that though it wouldn't harm to leave the code for `ITemplateStreamFilter` around for use by Trac < 1.4, the new suggested way also works great with earlier versions of Trac (1.0 and 1.2, perhaps even 0.12), so there's really no reason to maintain both versions once you did the switch.
     640Note that though we guarantee some level of support for the `ITemplateStreamFilter` during the transition period, the new suggested way also works great with earlier versions of Trac (1.0 and 1.2, perhaps even 0.12), so there's really no reason to maintain both versions once you did the switch.
     641
     642One strong incentive for dropping the `ITemplateStreamFilter` usage in your code is that by not doing so you basically **kill all the performance benefits** of the switch to Jinja2. The support of `ITemplateStreamFilter` implies that we first render the page to HTML using Jinja2, then parse it back as an HTML stream and feed this stream to the Genshi filter, so that it can be transformed, and then finally rendered again(!).
    618643
    619644The steps for replacing `filter_stream()` are the following:
     
    805830                req, 'query_results.html', data, None, fragment=True)
    806831}}}
    807 //implementing [source:cboos.git/trac/ticket/query.py@jinja2#L1403 Ticket Query] macro (''table'' mode)//
     832//implementing [source:cboos.git/trac/ticket/query.py@jinja2-trunk-r15341#L1425 Ticket Query] macro (''table'' mode)//
    808833
    809834A newer alternative is to use `Chrome.generate_template_fragment`, as in: