Jinjachecker
Jinja2 is very helpful when it detects any kind of error, as you always end up with a meaningful backtrace. Nevertheless, it can be tedious to get the nesting of control structures right. To help with that problem, we wrote the contrib/jinjachecker.py tool.
It first analyzes the Jinja2 control structures, and tries to provide some helpful diagnostics in case of nesting or stylistic errors. It also adds curly braces to the statements, so if you have an editor which can do matching of brace pairs, you can quickly spot the origin of a nesting problem.
Finally, while the indentation of the statements is free in Jinja2 templates, being consistent with it also helps to ensure a proper nesting.
Example
The command:
python contrib/jinjachecker.py trac/wiki/templates/wiki_view.html
outputs:
# -- Jinja2 check for 'trac/wiki/templates/wiki_view.html' 12 EXTENDS "jlayout.html" 18 {BLOCK title 19 {IF title: 21 }IF 22 }BLOCK title 25 {BLOCK head 26 SET modify_perm = 'WIKI_MODIFY' in perm(page.resource) 27 SET is_not_latest = page.exists and page.version != latest_version 31 {IF version or page.author == 'trac': 33 }IF 34 {IF modify_perm: 40 }IF 52 }BLOCK head 56 {BLOCK content 57 SET modify_perm = 'WIKI_MODIFY' in perm(page.resource) 58 SET create_perm = 'WIKI_CREATE' in perm(page.resource) 59 SET admin_perm = 'WIKI_ADMIN' in perm(page.resource) 60 SET is_not_latest = page.exists and page.version != latest_version 63 {IF version: 67 {WITH 68 SET version = page.version 69 SET author = authorinfo(page.author) 70 SET date = pretty_dateinfo(page.time) 71 SET hef = href.wiki(page.name, action='diff', version=page.version) 72 {TRANS version, author, date, href 77 }TRANS 78 }WITH 84 }IF 87 {IF page.exists: 91 SET last_modification = (page.comment and 97 {IF not version: 100 {WITH 101 SET href = href.wiki(page.name, action='diff', 103 SET date = pretty_dateinfo(page.time) 104 {TRANS href, last_modification, date 109 }TRANS 110 }WITH 116 }IF 117 ELSE: 119 {TRANS name = name_of(page.resource) 124 }TRANS 126 }IF 129 {WITH 130 SET alist = attachments 131 SET compact = True 132 SET foldable = True 133 INCLUDE "jlist_of_attachments.html" 134 }WITH 136 {WITH 137 SET delete_perm = 'WIKI_DELETE' in perm(page.resource) 138 SET rename_perm = 'WIKI_RENAME' in perm(page.resource) 139 {IF modify_perm or create_perm or delete_perm: 141 {IF modify_perm or create_perm: 145 {IF is_not_latest and modify_perm: 148 ELIF page.exists and modify_perm: 151 ELIF not page.exists and create_perm: 154 {IF templates: 161 {FOR t in sorted(templates): 165 }FOR 168 }IF 169 }IF 173 {IF page.exists: 174 {WITH alist = attachments 175 INCLUDE "jattach_file_form.html" 176 }WITH 177 }IF 178 }IF 180 {IF page.exists and rename_perm: 187 }IF 188 {IF page.exists and delete_perm: 193 {IF page.version == latest_version: 195 }IF 199 }IF 201 }IF 202 }WITH 204 {IF not page.exists and higher: 208 {FOR markup in higher: 210 }FOR 213 }IF 215 {IF not page.exists and related: 219 {FOR markup in related: 221 }FOR 224 }IF 230 }BLOCK content # -- Jinja2 OK
and:
# -- HTML check for 'trac/wiki/templates/jwiki_view.html' 1 ... 13 14 <!DOCTYPE html> 15 <html> 16 <head> 17 <title> 18 19 20 ${title} ${ super() } 21 22 23 </title> 24 25 26 27 28 29 ${ super() } 30 ... 52 53 </head> 54 55 <body> 56 57 58 59 60 61 <div id="content" class="${classes('wiki', create=not page.exists)}"> 62 ... 213 214 215 </div> 216 217 ${ super() } 218 219 220 </body> 221 </html> # -- HTML OK
The second part of this output is only generated if you have lxml installed. If that's the case, after having checked the Jinja2 syntax nesting in a first step, the jinjachecker tool removes the Jinja2 markup and performs a validation of the document using lxml in a second step.
Known Issues
The tool won't yet detect nesting mistakes when the Jinja2 control structure nesting and the HTML element nesting are both independently correct (e.g. errors like the one fixed in [68094c2ea/cboos.git] or r15508). This might be fixed in a 3rd pass, doing XML well-formedness check after having replaced the Jinja2 start/end keywords with "equivalent" XML elements.