--- a/bundled/jinja2/.hgtags Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/.hgtags Fri Jun 11 20:32:12 2010 -0400
@@ -6,3 +6,10 @@
b987be13b8f6603a2135e0f912e8aacb72f21181 2.2.1
2eb624b634a6bf62bc2b8e16a8eca3d41a515b34 2.3
140c54afc249d855745778f74011978bb9ba3439 2.3.1
+e3f873a9d3ffa75f147446db1cb580be2f6403dd 2.4
+d927a7499531e4c0f324a2dc34039f7c09877399 2.4.1
+3f3eadf15f616bf269a6bc2bd037a14e0faf3477 2.5
+3f3eadf15f616bf269a6bc2bd037a14e0faf3477 2.5
+0000000000000000000000000000000000000000 2.5
+0000000000000000000000000000000000000000 2.5
+0dd0062a64804df19c5bbcfc4fad860b2434e09b 2.5
--- a/bundled/jinja2/CHANGES Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/CHANGES Fri Jun 11 20:32:12 2010 -0400
@@ -1,16 +1,51 @@
Jinja2 Changelog
================
+Version 2.6
+-----------
+(codename to be selected, release date to be announced)
+
+- StopIteration exceptions raised by functions called from templates
+ are now intercepted and converted to undefineds. This solves a
+ lot of debugging grief. (StopIteration is used internally to
+ abort template execution)
+- improved performance of macro calls slightly.
+
+Version 2.5
+-----------
+(codename Incoherence, relased on May 29th 2010)
+
+- improved the sort filter (should have worked like this for a
+ long time) by adding support for case insensitive searches.
+- fixed a bug for getattribute constant folding.
+- support for newstyle gettext translations which result in a
+ nicer in-template user interface and more consistent
+ catalogs. (:ref:`newstyle-gettext`)
+- it's now possible to register extensions after an environment
+ was created.
+
+Version 2.4.1
+-------------
+(bugfix release, released on April 20th 2010)
+
+- fixed an error reporting bug for undefineds.
+
Version 2.4
-----------
-(codename to be selected, release date unknown)
+(codename Correlation, released on April 13th 2010)
- the environment template loading functions now transparently
pass through a template object if it was passed to it. This
makes it possible to import or extend from a template object
that was passed to the template.
-
+- added a :class:`ModuleLoader` that can load templates from
+ precompiled sources. The environment now features a method
+ to compile the templates from a configured loader into a zip
+ file or folder.
- the _speedups C extension now supports Python 3.
+- added support for autoescaping toggling sections and support
+ for evaluation contexts (:ref:`eval-context`).
+- extensions have a priority now.
Version 2.3.1
-------------
--- a/bundled/jinja2/MANIFEST.in Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/MANIFEST.in Fri Jun 11 20:32:12 2010 -0400
@@ -6,3 +6,7 @@
recursive-include examples *
recursive-include jinja2/testsuite/res *
recursive-exclude docs/_build/doctrees *
+recursive-exclude jinja2 *.pyc
+recursive-exclude docs *.pyc
+recursive-exclude jinja2 *.pyo
+recursive-exclude docs *.pyo
--- a/bundled/jinja2/artwork/jinjalogo.svg Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://web.resource.org/cc/"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="300"
- height="120"
- id="svg2"
- sodipodi:version="0.32"
- inkscape:version="0.45.1"
- version="1.0"
- sodipodi:docbase="/Users/mitsuhiko/Development/jinja2/artwork"
- sodipodi:docname="jinjalogo.svg"
- inkscape:export-filename="/Users/mitsuhiko/Development/jinja2/docs/_static/jinjabanner.png"
- inkscape:export-xdpi="60"
- inkscape:export-ydpi="60"
- inkscape:output_extension="org.inkscape.output.svg.inkscape">
- <defs
- id="defs4">
- <linearGradient
- id="linearGradient6558">
- <stop
- style="stop-color:#575757;stop-opacity:1;"
- offset="0"
- id="stop6560" />
- <stop
- style="stop-color:#2f2f2f;stop-opacity:1;"
- offset="1"
- id="stop6562" />
- </linearGradient>
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient6558"
- id="radialGradient6564"
- cx="61.297766"
- cy="60.910986"
- fx="61.297766"
- fy="60.910986"
- r="44.688254"
- gradientTransform="matrix(1,0,0,0.945104,0,3.343747)"
- gradientUnits="userSpaceOnUse" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient6558"
- id="radialGradient6580"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1,0,0,0.945104,0.355158,3.334402)"
- cx="61.297766"
- cy="60.910986"
- fx="61.297766"
- fy="60.910986"
- r="44.688254" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient6558"
- id="linearGradient4173"
- x1="255.15521"
- y1="32.347946"
- x2="279.8912"
- y2="32.347946"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.8073249,0,0,0.8073249,57.960878,7.4036303)" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient6558"
- id="linearGradient5145"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.7902775,0,0,0.82474,60.019977,8.0684132)"
- x1="255.15521"
- y1="32.347946"
- x2="279.8912"
- y2="32.347946" />
- </defs>
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- gridtolerance="10000"
- guidetolerance="10"
- objecttolerance="10"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="2.8"
- inkscape:cx="137.4752"
- inkscape:cy="57.574575"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- width="300px"
- height="120px"
- showguides="true"
- inkscape:guide-bbox="true"
- inkscape:window-width="1396"
- inkscape:window-height="900"
- inkscape:window-x="0"
- inkscape:window-y="22" />
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1">
- <path
- style="font-size:12px;font-style:normal;font-weight:normal;fill:#f4f4f4;fill-opacity:1;stroke:#e7e7e7;stroke-width:0.8;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;font-family:Bitstream Vera Sans;stroke-miterlimit:4;stroke-dasharray:none"
- d="M 165.36463,80.874808 L 165.36463,80.874808 L 153.32556,80.874808 L 153.32556,81.8344 L 147.64994,81.8344 L 147.64994,36.035583 L 165.36463,36.035583 L 165.36463,20.333129 C 170.58154,21.031083 173.07533,22.077914 172.84609,23.473621 C 172.78871,24.055258 172.21545,24.549594 171.12624,24.956624 L 171.12624,36.035583 L 189.09895,36.035583 L 189.09895,82.532286 L 183.33733,82.532286 L 183.33733,80.874808 L 171.12624,80.874808 L 171.12624,102.94548 L 165.36463,102.94548 L 165.36463,80.874808 M 153.32556,55.489173 L 153.32556,55.489173 L 165.36463,55.489173 L 165.36463,41.793146 L 153.32556,41.793146 L 153.32556,55.489173 M 171.12624,55.489173 L 171.12624,55.489173 L 183.33733,55.489173 L 183.33733,41.793146 L 171.12624,41.793146 L 171.12624,55.489173 M 183.33733,61.333977 L 183.33733,61.333977 L 171.12624,61.333977 L 171.12624,75.030006 L 183.33733,75.030006 L 183.33733,61.333977 M 165.36463,61.333977 L 165.36463,61.333977 L 153.32556,61.333977 L 153.32556,75.030006 L 165.36463,75.030006 L 165.36463,61.333977 M 132.85897,59.414792 C 137.33069,63.136883 140.99969,67.934848 143.86618,73.808701 L 139.13654,77.385372 C 137.24467,72.965445 134.6362,69.12707 131.31114,65.87024 L 131.31114,102.94548 L 125.63554,102.94548 L 125.63554,68.57455 C 122.31042,71.947693 118.52671,74.913707 114.28436,77.47261 L 109.64069,73.372526 C 121.50782,67.091566 130.62312,55.489212 136.98668,38.565417 L 116.26221,38.565417 L 116.26221,32.720615 L 125.80754,32.720615 L 125.80754,20.333129 C 130.85245,21.031083 133.31761,22.048838 133.20299,23.386383 C 133.14561,24.026183 132.57235,24.549594 131.48307,24.956624 L 131.48307,32.720615 L 140.77043,32.720615 L 143.60824,36.733469 C 140.68444,45.51526 137.10137,53.075692 132.85897,59.414792 M 254.11016,49.469901 L 254.11016,49.469901 L 254.11016,20.333129 C 259.21243,21.031083 261.67755,22.048838 261.50562,23.386383 C 261.44823,23.909869 261.04699,24.346044 260.30172,24.694917 C 260.30164,24.694986 260.30164,24.694986 260.30172,24.694917 L 260.30172,24.694917 L 259.78578,24.956624 L 259.78578,49.469901 L 277.15652,49.469901 L 277.15652,55.227471 L 259.78578,55.227471 L 259.78578,93.785712 L 281.45616,93.785712 L 281.45616,99.63051 L 232.35378,99.63051 L 232.35378,93.785712 L 254.11016,93.785712 L 254.11016,55.227471 L 236.22346,55.227471 L 236.22346,49.469901 L 254.11016,49.469901 M 225.5603,59.327554 C 231.12111,63.107798 235.62145,67.876693 239.06127,73.634235 L 234.76157,77.647079 C 231.60845,72.180322 227.82475,67.934848 223.41044,64.910648 L 223.41044,102.94548 L 217.73484,102.94548 L 217.73484,67.44049 C 212.91919,71.627831 207.70222,75.030021 202.084,77.647079 L 197.87027,73.198053 C 212.66118,66.917101 224.01239,55.372897 231.92377,38.565417 L 205.35172,38.565417 L 205.35172,32.720615 L 217.99283,32.720615 L 217.99283,20.333129 C 223.03774,21.031083 225.50291,22.048838 225.38829,23.386383 C 225.33089,24.026183 224.75765,24.549594 223.66837,24.956624 L 223.66837,32.720615 L 236.22346,32.720615 L 238.80326,36.733469 C 235.13421,45.51526 230.71987,53.046611 225.5603,59.327554"
- id="text4761" />
- <path
- style="font-size:44.09793472px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#b41717;fill-opacity:1;stroke:#7f2828;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Candara;stroke-miterlimit:4;stroke-dasharray:none"
- d="M 149.14708,37.774469 C 148.97807,41.117899 148.84526,44.824225 148.74871,48.893456 C 148.67626,52.962754 148.3818,70.641328 148.38184,75.524422 C 148.3818,79.065795 148.05588,81.991266 147.40406,84.300835 C 146.75219,86.610422 145.72612,88.557071 144.32585,90.140779 C 142.94969,91.724494 141.17522,92.901283 139.00239,93.671139 C 136.82953,94.440996 134.22211,94.825935 131.18014,94.825935 C 128.83828,94.825935 126.73787,94.59498 124.87889,94.133049 L 125.4221,89.31593 C 127.13623,90.0418 128.92278,90.404734 130.78177,90.404733 C 132.85805,90.404734 134.66875,90.140782 136.2139,89.612876 C 137.78315,89.062981 139.02651,88.216133 139.94396,87.072335 C 140.8855,85.928548 141.54942,84.520804 141.93572,82.8491 C 142.34613,81.177412 142.55134,78.988811 142.55136,76.283285 C 142.55134,66.297119 142.62852,44.659257 142.26641,37.774469 L 149.14708,37.774469 M 166.38498,80.732697 L 159.83024,80.732697 C 160.16821,76.333498 160.33723,71.307412 160.33723,65.654424 C 160.33723,59.2976 159.91471,53.963567 159.06973,49.652319 L 166.31257,48.761483 C 166.02284,53.358679 165.87799,58.98965 165.87799,65.654424 C 165.87799,70.933479 166.04699,75.959565 166.38498,80.732697 M 167.90601,39.490159 C 167.90598,40.611994 167.5076,41.590815 166.7109,42.42662 C 165.91418,43.240515 164.79155,43.647442 163.343,43.647399 C 162.11172,43.647442 161.146,43.295504 160.44588,42.591595 C 159.76988,41.865769 159.43188,40.996927 159.43188,39.98507 C 159.43188,38.885304 159.84231,37.928485 160.66315,37.114591 C 161.48399,36.30078 162.61869,35.893853 164.06727,35.893811 C 165.25023,35.893853 166.17975,36.256783 166.85575,36.982609 C 167.55588,37.686526 167.90598,38.522373 167.90601,39.490159 M 206.72748,80.732697 L 200.13651,80.732697 C 200.66763,74.947749 200.93319,68.634899 200.9332,61.794122 C 200.93319,58.406756 200.1727,56.097177 198.65174,54.865371 C 197.15487,53.61163 195.00619,52.984747 192.20564,52.984714 C 188.77731,52.984747 185.61465,54.117535 182.71753,56.383099 C 182.71753,63.883761 182.76583,72.000287 182.86238,80.732697 L 176.27142,80.732697 C 176.68182,73.254058 176.88707,67.843042 176.88707,64.499632 C 176.88707,59.352589 176.3559,54.359493 175.29363,49.520339 L 181.66734,48.695493 L 182.35539,52.720761 L 182.64511,52.720761 C 186.21823,49.773323 190.04483,48.299592 194.12499,48.299567 C 198.13265,48.299592 201.23499,49.113454 203.43201,50.741118 C 205.62895,52.346863 206.72747,55.217334 206.72748,59.352563 C 206.72747,59.770507 206.70331,60.595362 206.65507,61.827118 C 206.60675,63.058915 206.5826,63.883761 206.58262,64.30167 C 206.5826,67.975018 206.63088,73.452022 206.72748,80.732697 M 222.69791,48.695493 C 222.28747,55.514282 222.08225,62.355041 222.08225,69.21778 C 222.08225,71.043461 222.14262,73.463019 222.26332,76.476468 C 222.40822,79.467925 222.4806,81.502559 222.48063,82.580363 C 222.4806,89.685068 219.51105,93.996287 213.57195,95.514024 L 211.76124,93.006484 C 213.90995,91.356766 215.2378,89.597085 215.74478,87.727431 C 216.49321,85.043912 216.86743,79.324953 216.86743,70.570535 C 216.86743,61.178248 216.3846,54.16153 215.41887,49.520339 L 222.69791,48.695493 M 224.2551,39.490159 C 224.2551,40.611994 223.85673,41.590815 223.06006,42.42662 C 222.26332,43.240515 221.14069,43.647442 219.69213,43.647399 C 218.46084,43.647442 217.49515,43.295504 216.795,42.591595 C 216.119,41.865769 215.781,40.996927 215.781,39.98507 C 215.781,38.885304 216.19144,37.928485 217.01231,37.114591 C 217.83316,36.30078 218.96785,35.893853 220.4164,35.893811 C 221.5994,35.893853 222.52889,36.256783 223.20492,36.982609 C 223.90503,37.686526 224.2551,38.522373 224.2551,39.490159 M 259.60008,80.732697 L 253.91446,80.930661 C 253.62473,79.852857 253.47987,78.830045 253.4799,77.862216 L 253.11774,77.862216 C 250.14817,80.325772 246.10427,81.557546 240.98606,81.557547 C 238.20962,81.557546 235.8195,80.820682 233.81563,79.346948 C 231.81178,77.851221 230.80988,75.728607 230.80988,72.979099 C 230.80988,69.591724 232.37914,66.875216 235.51769,64.829574 C 238.65625,62.761967 244.48667,61.67316 253.00913,61.563165 C 253.08155,61.035275 253.11772,60.430386 253.11774,59.748497 C 253.11772,57.043003 252.32104,55.239336 250.72765,54.337474 C 249.15832,53.435661 246.76819,52.984747 243.55721,52.984714 C 239.76681,52.984747 236.03678,53.413668 232.3671,54.271484 L 232.9827,49.718301 C 236.60411,48.77251 240.76873,48.299592 245.47658,48.299567 C 249.77395,48.299592 253.09359,49.113454 255.43545,50.741118 C 257.77728,52.346863 258.94819,55.096363 258.94824,58.989625 C 258.94819,60.023469 258.88785,61.904117 258.76715,64.631608 C 258.67054,67.337133 258.62228,69.140806 258.6223,70.042632 C 258.62228,74.045913 258.94819,77.609265 259.60008,80.732697 M 253.19019,74.331856 C 253.06945,70.988469 253.00909,67.986016 253.00913,65.324484 C 248.47027,65.324498 245.01786,65.632443 242.65187,66.248318 C 238.69248,67.348131 236.71278,69.448748 236.71278,72.550177 C 236.71278,75.541643 239.03044,77.037371 243.66588,77.037366 C 247.64942,77.037371 250.82416,76.135534 253.19019,74.331856"
- id="text3736"
- sodipodi:nodetypes="ccsscssccscccsccccsccsccsscsssccccscscccsccccscsssccscscccscccsscsssccccccscsccscsccscscsccccssc" />
- <path
- style="fill:url(#radialGradient6564);fill-opacity:1.0;fill-rule:evenodd;stroke:#323232;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
- d="M 105.45673,18.675923 C 105.45673,18.675923 88.211949,26.918461 74.172834,28.737898 C 60.133727,30.557333 33.360434,32.377571 28.045622,31.093256 C 22.730818,29.808941 18.915645,28.309196 18.915645,28.309196 L 20.021441,32.056583 L 16.609513,35.052471 L 17.2144,36.121726 L 18.61792,36.22764 L 22.92773,36.762252 L 23.532621,38.688909 L 25.937975,38.905784 L 27.143021,42.970927 C 27.143021,42.970927 32.254764,43.399628 33.758953,43.399628 C 35.263142,43.399628 38.271966,43.187802 38.271966,43.187802 L 38.371202,44.791657 L 39.477002,45.003495 L 39.477002,46.824227 L 37.066917,48.967759 L 37.671807,49.073671 L 37.671807,49.820127 C 37.671807,49.820127 32.255457,50.252157 30.049301,49.93109 C 27.843157,49.610006 27.440747,49.608286 27.440747,49.608286 L 27.242258,49.820127 L 27.143021,50.783455 L 27.643946,50.783455 L 27.84242,54.959544 L 38.976091,54.530844 L 38.172728,68.980747 L 38.073481,70.796442 L 28.645781,70.261816 L 28.546544,66.408513 L 30.649462,66.408513 L 30.852673,64.910557 L 32.757107,64.481857 L 33.059555,64.058192 L 25.937975,62.343374 L 20.522364,63.947229 L 21.42496,64.698732 L 22.327572,64.698732 L 22.426809,65.984848 L 24.331254,66.09076 L 24.331254,69.838147 L 22.228335,70.372777 L 22.630009,71.225146 L 23.130934,71.547931 L 23.130934,74.437917 L 24.435218,74.437917 L 24.435218,87.813529 L 22.327572,88.13632 L 22.630009,91.989617 L 23.929569,92.206492 L 23.731093,100.98236 L 29.449141,101.08826 L 28.244105,92.418334 L 36.868446,92.206492 L 36.268285,96.912181 L 35.464925,100.23086 L 44.188501,100.33677 L 44.287739,91.777793 L 50.303506,91.243181 L 50.005786,96.700351 L 49.802585,99.90807 L 54.920484,99.90807 L 54.717274,91.132217 L 55.421397,91.243181 L 55.619882,87.067076 L 54.816521,87.067076 L 54.518798,85.352258 L 54.017874,80.429702 L 54.216359,74.760706 L 55.31743,74.760706 L 55.31743,71.336105 L 53.913913,71.442015 L 54.117112,67.402096 L 55.747469,67.240708 L 55.823083,65.929374 L 56.749319,65.793192 L 57.699176,65.071956 L 51.985842,63.896802 L 46.31977,65.15265 L 46.872668,66.060507 L 47.47283,66.010066 L 48.172228,65.984848 L 48.299828,67.639144 L 49.878196,67.563497 L 49.906548,71.144447 L 43.111042,70.988097 L 43.337879,67.160002 L 43.559978,63.679927 L 43.559978,59.105378 L 43.763188,54.288748 L 57.373101,53.592733 L 73.567955,52.659674 L 73.71917,55.736265 L 73.142647,63.120082 L 72.892183,69.9945 L 66.928387,69.888585 L 66.900039,65.071956 L 69.106918,64.991267 L 69.206169,63.629486 L 70.108765,63.493308 L 70.061506,63.226006 L 70.964116,63.175568 L 71.465028,62.504773 L 64.721507,60.926122 L 58.001612,62.368592 L 58.4789,63.200785 L 59.230285,63.1453 L 59.230285,63.523577 L 60.156518,63.523577 L 60.156518,65.046738 L 62.136575,65.071956 L 62.112937,69.298485 L 60.109259,69.298485 L 60.080907,70.261816 L 60.785031,70.342507 L 60.70942,74.009202 L 62.188552,74.089909 L 62.013701,88.620507 L 60.057282,89.018952 L 60.080907,89.714967 L 60.761406,89.714967 L 60.761406,93.437137 L 61.886113,93.437137 L 61.588391,98.52109 L 61.210343,102.95945 L 68.331912,103.14605 L 68.105084,99.29275 L 67.580538,96.085028 L 67.476575,93.300955 L 73.520696,93.195041 L 73.345845,97.502272 L 73.317494,102.05159 L 76.729426,102.3189 L 81.3653,102.1323 L 82.820807,101.70358 L 82.017437,99.26753 L 81.818959,95.439438 L 81.440912,92.710853 L 87.206218,92.499027 L 86.955759,95.842931 L 86.932133,101.08826 L 89.238253,101.30009 L 91.520751,101.24965 L 92.621828,100.90165 L 91.969693,95.923633 L 91.747577,92.176239 L 92.725793,92.070324 L 92.749427,88.726422 L 93.02352,88.670945 L 92.976244,87.949712 L 91.846823,87.949712 L 91.619996,85.488427 L 91.520751,74.811143 L 92.371377,74.785924 L 92.371377,71.280616 L 92.725793,71.336105 L 92.725793,70.640088 L 91.468773,70.529127 L 91.497126,66.463987 L 93.600043,66.277382 L 93.477182,64.910557 L 94.403419,64.829863 L 94.351424,64.562549 L 95.580099,63.947229 L 89.337489,62.69138 L 82.995657,63.977495 L 83.39733,64.723951 L 84.375543,64.643256 L 84.427528,64.966046 L 85.254515,64.966046 L 85.301775,66.569901 L 87.357445,66.544681 L 87.532293,70.478688 L 80.264217,70.423216 L 79.413593,64.512124 L 78.733106,61.380041 L 78.184923,55.761484 L 78.510996,52.473053 L 92.999878,51.373557 L 93.047136,46.476221 L 93.774891,46.289613 L 93.727651,45.543159 L 93.174743,45.220372 C 93.174629,45.220372 85.252181,46.395266 82.745197,46.66284 C 82.0389,46.738209 82.09239,46.733258 81.516524,46.79397 L 81.440912,45.886118 L 78.444837,44.317564 L 78.482644,42.491786 L 79.512842,42.461518 L 79.588444,39.949808 C 79.588444,39.949808 85.728225,39.546834 88.009582,39.0117 C 90.290937,38.476559 93.524432,37.942456 93.524432,37.942456 L 95.055545,33.79662 L 98.089437,32.913987 L 98.339888,32.217972 L 105.20628,30.316548 L 105.98602,29.676006 L 103.37744,23.976741 L 103.62792,22.690624 L 104.95584,21.994611 L 105.91041,19.079404 L 105.45673,18.675923 z M 72.466874,40.403728 L 72.429067,42.476654 L 73.983813,42.542211 L 73.884576,44.509221 L 70.836515,46.506487 L 70.647496,47.081457 L 71.876167,47.091543 L 71.866712,47.575729 L 62.552432,48.029652 L 62.613863,46.652742 L 63.039175,45.966809 L 63.067524,45.528025 L 63.07698,44.579832 L 63.341609,43.949374 L 63.440849,43.439982 L 63.440849,43.076841 L 63.842533,41.47297 L 72.466874,40.403728 z M 52.987688,42.168984 L 52.760853,43.561027 L 53.488599,44.418431 L 53.441349,45.916386 L 54.117112,46.960408 L 53.942262,48.191039 L 54.443185,48.912273 L 44.939872,49.2855 L 44.916247,48.967759 L 46.017333,48.831579 L 46.069307,48.428097 L 43.66394,47.121797 L 43.536351,45.03375 L 44.689411,44.978276 L 44.788661,42.72883 L 52.987688,42.168984 z M 67.051262,74.276518 L 72.81657,74.649742 L 72.618099,82.411833 L 73.36947,88.776857 L 67.254465,88.565018 L 67.051262,74.276518 z M 28.44258,74.599304 L 37.671807,75.078442 L 36.868446,80.429702 L 36.868446,84.928593 L 37.520583,87.440302 L 28.494569,87.869006 L 28.44258,74.599304 z M 87.508658,74.649742 L 87.508658,87.924488 L 81.644113,88.353194 L 81.440912,81.342592 L 80.788764,74.811143 L 87.508658,74.649742 z M 43.087416,74.947312 L 49.906548,74.972531 L 49.977434,87.278902 L 43.611966,87.389863 L 43.285891,83.400379 L 43.262266,79.441156 L 43.087416,74.947312 z "
- id="path4735" />
- </g>
-</svg>
--- a/bundled/jinja2/docs/Makefile Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " changes to make an overview over all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
-
-clean:
- -rm -rf _build/*
-
-html:
- mkdir -p _build/html _build/doctrees
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
- @echo
- @echo "Build finished. The HTML pages are in _build/html."
-
-pickle:
- mkdir -p _build/pickle _build/doctrees
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
- @echo
- @echo "Build finished; now you can process the pickle files"
-
-json:
- mkdir -p _build/json _build/doctrees
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json
- @echo
- @echo "Build finished; now you can process the json files"
-
-web: pickle
-
-htmlhelp:
- mkdir -p _build/htmlhelp _build/doctrees
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in _build/htmlhelp."
-
-latex:
- mkdir -p _build/latex _build/doctrees
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
- @echo
- @echo "Build finished; the LaTeX files are in _build/latex."
- @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
- "run these through (pdf)latex."
-
-changes:
- mkdir -p _build/changes _build/doctrees
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes
- @echo
- @echo "The overview file is in _build/changes."
-
-linkcheck:
- mkdir -p _build/linkcheck _build/doctrees
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in _build/linkcheck/output.txt."
Binary file bundled/jinja2/docs/_static/darkmetal.png has changed
Binary file bundled/jinja2/docs/_static/headerbg.png has changed
Binary file bundled/jinja2/docs/_static/implementation.png has changed
--- a/bundled/jinja2/docs/_static/jinja.js Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-$(function() {
-
- var
- toc = $('#toc').show(),
- items = $('#toc > ul').hide();
-
- $('#toc h3')
- .click(function() {
- if (items.is(':visible')) {
- items.animate({
- height: 'hide',
- opacity: 'hide'
- }, 300, function() {
- toc.removeClass('expandedtoc');
- });
- }
- else {
- items.animate({
- height: 'show',
- opacity: 'show'
- }, 400);
- toc.addClass('expandedtoc');
- }
- });
-
-});
Binary file bundled/jinja2/docs/_static/jinjabanner.png has changed
Binary file bundled/jinja2/docs/_static/metal.png has changed
Binary file bundled/jinja2/docs/_static/navigation.png has changed
Binary file bundled/jinja2/docs/_static/note.png has changed
--- a/bundled/jinja2/docs/_static/print.css Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-div.header, div.relnav, #toc { display: none; }
-#contentwrapper { padding: 0; margin: 0; border: none; }
-body { color: black; background-color: white; }
-div.footer { border-top: 1px solid #888; color: #888; margin-top: 1cm; }
-div.footer a { text-decoration: none; }
--- a/bundled/jinja2/docs/_static/style.css Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,390 +0,0 @@
-body {
- background-color: #222;
- margin: 0;
- padding: 0;
- font-family: 'Georgia', serif;
- font-size: 15px;
- color: #eee;
-}
-
-div.footer {
- border-top: 1px solid #111;
- padding: 8px;
- font-size: 11px;
- text-align: center;
- letter-spacing: 0.5px;
-}
-
-div.footer a {
- color: #eee;
-}
-
-div.header {
- margin: 0 -15px 0 -15px;
- background: url(headerbg.png) repeat-x;
- border-top: 6px solid #D20000;
-}
-
-div.relnav {
- border-bottom: 1px solid #111;
- background: url(navigation.png);
- margin: 0 -15px 0 -15px;
- padding: 2px 20px 0 28px;
- line-height: 25px;
- color: #aaa;
- font-size: 12px;
- text-align: center;
-}
-
-div.relnav a {
- color: #eee;
- font-weight: bold;
- text-decoration: none;
-}
-
-div.relnav a:hover {
- text-decoration: underline;
-}
-
-#content {
- background-color: white;
- color: #111;
- border-bottom: 1px solid black;
- background: url(watermark.png) center 0;
- padding: 0 15px 0 15px;
- margin: 0;
-}
-
-h1 {
- margin: 0;
- padding: 15px 0 0 0;
-}
-
-h1.heading {
- margin: 0;
- padding: 0;
- height: 80px;
-}
-
-h1.heading:hover {
- background: #222;
-}
-
-h1.heading a {
- background: url(jinjabanner.png) no-repeat center 0;
- display: block;
- width: 100%;
- height: 80px;
-}
-
-h1.heading a:focus {
- -moz-outline: none;
- outline: none;
-}
-
-h1.heading span {
- display: none;
-}
-
-#jinjalogo {
- background-image: url(jinjalogo.png);
- background-repeat: no-repeat;
- width: 400px;
- height: 160px;
-}
-
-#contentwrapper {
- max-width: 680px;
- padding: 0 18px 20px 18px;
- margin: 0 auto 0 auto;
- border-right: 1px solid #eee;
- border-left: 1px solid #eee;
- background: url(watermark_blur.png) center -114px;
-}
-
-#contentwrapper h2,
-#contentwrapper h2 a {
- color: #222;
- font-size: 24px;
- margin: 20px 0 0 0;
-}
-
-#contentwrapper h3,
-#contentwrapper h3 a {
- color: #b41717;
- font-size: 20px;
- margin: 20px 0 0 0;
-}
-
-table.docutils {
- border-collapse: collapse;
- border: 2px solid #aaa;
- margin: 0.5em 1.5em 0.5em 1.5em;
-}
-
-table.docutils td {
- padding: 2px;
- border: 1px solid #ddd;
-}
-
-p, li, dd, dt, blockquote {
- color: #333;
-}
-
-blockquote {
- margin: 10px 0 10px 20px;
-}
-
-p {
- line-height: 20px;
- margin-bottom: 0;
- margin-top: 10px;
-}
-
-hr {
- border-top: 1px solid #ccc;
- border-bottom: 0;
- border-right: 0;
- border-left: 0;
- margin-bottom: 10px;
- margin-top: 20px;
-}
-
-dl {
- margin-left: 10px;
-}
-
-li, dt {
- margin-top: 5px;
-}
-
-dt {
- font-weight: bold;
- color: #000;
-}
-
-dd {
- margin-top: 10px;
- line-height: 20px;
-}
-
-th {
- text-align: left;
- padding: 3px;
- background-color: #f2f2f2;
-}
-
-a {
- color: #b41717;
-}
-
-a:hover {
- color: #444;
-}
-
-pre {
- background: #ededed url(metal.png);
- border-top: 1px solid #ccc;
- border-bottom: 1px solid #ccc;
- padding: 5px;
- font-size: 13px;
- font-family: 'Bitstream Vera Sans Mono', 'Monaco', monospace;
-}
-
-tt {
- font-size: 13px;
- font-family: 'Bitstream Vera Sans Mono', 'Monaco', monospace;
- color: black;
- padding: 1px 2px 1px 2px;
- background-color: #fafafa;
- border-bottom: 1px solid #eee;
-}
-
-a.reference:hover tt {
- border-bottom-color: #aaa;
-}
-
-cite {
- /* abusing <cite>, it's generated by ReST for `x` */
- font-size: 13px;
- font-family: 'Bitstream Vera Sans Mono', 'Monaco', monospace;
- font-weight: bold;
- font-style: normal;
-}
-
-div.admonition {
- margin: 10px 0 10px 0;
- padding: 10px 10px 10px 60px;
- border: 1px solid #ccc;
-}
-
-div.admonition p.admonition-title {
- background-color: #b41717;
- color: white;
- margin: -10px -10px 10px -60px;
- padding: 4px 10px 4px 10px;
- font-weight: bold;
- font-size: 15px;
-}
-
-div.admonition p.admonition-title a {
- color: white!important;
-}
-
-div.admonition-note {
- background: url(note.png) no-repeat 10px 40px;
-}
-
-div.admonition-implementation {
- background: url(implementation.png) no-repeat 10px 40px;
-}
-
-a.headerlink {
- color: #B4B4B4!important;
- font-size: 0.8em;
- padding: 0 4px 0 4px;
- text-decoration: none!important;
- visibility: hidden;
-}
-
-h1:hover > a.headerlink,
-h2:hover > a.headerlink,
-h3:hover > a.headerlink,
-h4:hover > a.headerlink,
-h5:hover > a.headerlink,
-h6:hover > a.headerlink,
-dt:hover > a.headerlink,
-dt:hover > a.headerlink {
- visibility: visible;
-}
-
-a.headerlink:hover {
- background-color: #B4B4B4;
- color: #F0F0F0!important;
-}
-
-table.indextable {
- width: 100%;
-}
-
-table.indextable td {
- vertical-align: top;
- width: 50%;
-}
-
-table.indextable dl dd {
- font-size: 11px;
-}
-
-table.indextable dl dd a {
- color: #000;
-}
-
-dl.function dt,
-dl.class dt,
-dl.exception dt,
-dl.method dt,
-dl.attribute dt {
- font-weight: normal;
-}
-
-dt .descname {
- font-weight: bold;
- margin-right: 4px;
-}
-
-dt .descname, dt .descclassname {
- padding: 0;
- background: transparent;
- border-bottom: 1px solid #111;
-}
-
-dt .descclassname {
- margin-left: 2px;
-}
-
-dl dt big {
- font-size: 100%;
-}
-
-ul.search {
- margin: 10px 0 0 30px;
- padding: 0;
-}
-
-ul.search li {
- margin: 10px 0 0 0;
- padding: 0;
-}
-
-ul.search div.context {
- font-size: 12px;
- padding: 4px 0 0 20px;
- color: #888;
-}
-
-span.highlight {
- background-color: #eee;
- border: 1px solid #ccc;
-}
-
-#toc {
- margin: 0 -17px 0 -17px;
- display: none;
-}
-
-#toc h3 {
- float: right;
- margin: 5px 5px 0 0;
- padding: 0;
- font-size: 12px;
- color: #777;
-}
-
-#toc h3:hover {
- color: #333;
- cursor: pointer;
-}
-
-.expandedtoc {
- background: #222 url(darkmetal.png);
- border-bottom: 1px solid #111;
- outline-bottom: 1px solid #000;
- padding: 5px;
-}
-
-.expandedtoc h3 {
- color: #aaa;
- margin: 0!important;
-}
-
-.expandedtoc h3:hover {
- color: white!important;
-}
-
-#tod h3:hover {
- color: white;
-}
-
-#toc a {
- color: #ddd;
- text-decoration: none;
-}
-
-#toc a:hover {
- color: white;
- text-decoration: underline;
-}
-
-#toc ul {
- margin: 5px 0 12px 17px;
- padding: 0 7px 0 7px;
-}
-
-#toc ul ul {
- margin-bottom: 0;
-}
-
-#toc ul li {
- margin: 2px 0 0 0;
-}
Binary file bundled/jinja2/docs/_static/watermark.png has changed
Binary file bundled/jinja2/docs/_static/watermark_blur.png has changed
--- a/bundled/jinja2/docs/_templates/genindex.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-{% extends "layout.html" %}
-{% set title = 'Index' %}
-{% block body %}
-
- <h1 id="index">Index</h1>
-
- {% for key, dummy in genindexentries -%}
- <a href="#{{ key }}"><strong>{{ key }}</strong></a> {% if not loop.last %}| {% endif %}
- {%- endfor %}
- <hr>
-
- {% for key, entries in genindexentries %}
- <h2 id="{{ key }}">{{ key }}</h2>
- <table class="indextable"><tr>
- {%- for column in entries|slice(2) if column %}
- <td><dl>
- {%- for entryname, (links, subitems) in column %}
- <dt>{% if links %}<a href="{{ links[0] }}">{{ entryname|e }}</a>
- {% for link in links[1:] %}, <a href="{{ link }}">[Link]</a>{% endfor %}
- {%- else %}{{ entryname|e }}{% endif %}</dt>
- {%- if subitems %}
- <dd><dl>
- {%- for subentryname, subentrylinks in subitems %}
- <dt><a href="{{ subentrylinks[0] }}">{{ subentryname|e }}</a>
- {%- for link in subentrylinks[1:] %}, <a href="{{ link }}">[Link]</a>{% endfor -%}
- </dt>
- {%- endfor %}
- </dl></dd>
- {%- endif -%}
- {%- endfor %}
- </dl></td>
- {%- endfor %}
- </tr></table>
- {% endfor %}
-
-{% endblock %}
--- a/bundled/jinja2/docs/_templates/layout.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
- <head>
- <title>Jinja2 Documentation</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <link rel="stylesheet" href="{{ pathto('_static/style.css', 1) }}" type="text/css">
- <link rel="stylesheet" href="{{ pathto('_static/print.css', 1) }}" type="text/css" media="print">
- <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css">
- {%- if builder != 'htmlhelp' %}
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: '{{ pathto("", 1) }}',
- VERSION: '{{ release }}'
- };
- </script>
- <script type="text/javascript" src="{{ pathto('_static/jquery.js', 1) }}"></script>
- <script type="text/javascript" src="{{ pathto('_static/interface.js', 1) }}"></script>
- <script type="text/javascript" src="{{ pathto('_static/doctools.js', 1) }}"></script>
- <script type="text/javascript" src="{{ pathto('_static/jinja.js', 1) }}"></script>
- {%- endif %}
- {%- if use_opensearch and builder != 'htmlhelp' %}
- <link rel="search" type="application/opensearchdescription+xml"
- title="Search within {{ docstitle }}"
- href="{{ pathto('_static/opensearch.xml', 1) }}">
- {%- endif %}
- {%- if hasdoc('about') %}
- <link rel="author" title="About these documents" href="{{ pathto('about') }}">
- {%- endif %}
- <link rel="contents" title="Global table of contents" href="{{ pathto('contents') }}">
- <link rel="index" title="Global index" href="{{ pathto('genindex') }}">
- <link rel="search" title="Search" href="{{ pathto('search') }}">
- {%- if hasdoc('copyright') %}
- <link rel="copyright" title="Copyright" href="{{ pathto('copyright') }}">
- {%- endif %}
- <link rel="top" title="{{ docstitle }}" href="{{ pathto('index') }}">
- {%- if parents %}
- <link rel="up" title="{{ parents[-1].title|striptags }}" href="{{ parents[-1].link|e }}">
- {%- endif %}
- {%- if next %}
- <link rel="next" title="{{ next.title|striptags }}" href="{{ next.link|e }}">
- {%- endif %}
- {%- if prev %}
- <link rel="prev" title="{{ prev.title|striptags }}" href="{{ prev.link|e }}">
- {%- endif %}
- {% block extrahead %}{% endblock %}
- </head>
- <body>
- <div id="content">
- <div class="header">
- <h1 class="heading"><a href="{{ pathto('index') }}"
- title="back to the documentation overview"><span>Jinja</span></a></h1>
- </div>
- <div class="relnav">
- {%- if prev %}
- <a href="{{ prev.link|e }}">« {{ prev.title }}</a> |
- {%- endif %}
- <a href="{{ pathto(current_page_name) if current_page_name else '#' }}">{{ title }}</a>
- {%- if next %}
- | <a href="{{ next.link|e }}">{{ next.title }} »</a>
- {%- endif %}
- </div>
- <div id="contentwrapper">
- {%- if display_toc %}
- <div id="toc">
- <h3>Table Of Contents</h3>
- {{ toc }}
- </div>
- {%- endif %}
- {% block body %}{% endblock %}
- </div>
- </div>
- <div class="footer">
- © Copyright 2008 by the <a href="http://pocoo.org/">Pocoo Team</a>,
- documentation generated by <a href="http://sphinx.pocoo.org/">Sphinx</a>
- </div>
- </body>
-</html>
--- a/bundled/jinja2/docs/_templates/opensearch.xml Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
- <ShortName>{{ project }}</ShortName>
- <Description>Search {{ docstitle }}</Description>
- <InputEncoding>utf-8</InputEncoding>
- <Url type="text/html" method="get"
- template="{{ use_opensearch }}/{{ pathto('search') }}?q={searchTerms}&check_keywords=yes&area=default"/>
- <LongName>{{ docstitle }}</LongName>
-</OpenSearchDescription>
--- a/bundled/jinja2/docs/_templates/page.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-{% extends 'layout.html' %}
-{% block body %}
- {{ body }}
-{% endblock %}
--- a/bundled/jinja2/docs/_templates/search.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-{% extends "layout.html" %}
-{% set title = 'Search' %}
-{% block extrahead %}
- <script type="text/javascript" src="{{ pathto('_static/searchtools.js', 1) }}"></script>
-{% endblock %}
-{% block body %}
- <h1 id="search-documentation">Search</h1>
- <p>
- From here you can search these documents. Enter your search
- words into the box below and click "search". Note that the search
- function will automatically search for all of the words. Pages
- containing less words won't appear in the result list.
- </p>
- <form action="" method="get"><p>
- <input type="text" name="q" value="">
- <input type="submit" value="search">
- </p></form>
- {% if search_performed %}
- <h2>Search Results</h2>
- {% if not search_results %}
- <p>Your search did not match any results.</p>
- {% endif %}
- {% endif %}
- <div id="search-results">
- {% if search_results %}
- <ul>
- {% for href, caption, context in search_results %}
- <li><a href="{{ pathto(item.href) }}">{{ caption }}</a>
- <div class="context">{{ context|e }}</div>
- </li>
- {% endfor %}
- </ul>
- {% endif %}
- </div>
-{% endblock %}
--- a/bundled/jinja2/docs/api.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,684 +0,0 @@
-API
-===
-
-.. module:: jinja2
- :synopsis: public Jinja2 API
-
-This document describes the API to Jinja2 and not the template language. It
-will be most useful as reference to those implementing the template interface
-to the application and not those who are creating Jinja2 templates.
-
-Basics
-------
-
-Jinja2 uses a central object called the template :class:`Environment`.
-Instances of this class are used to store the configuration, global objects
-and are used to load templates from the file system or other locations.
-Even if you are creating templates from strings by using the constructor of
-:class:`Template` class, an environment is created automatically for you,
-albeit a shared one.
-
-Most applications will create one :class:`Environment` object on application
-initialization and use that to load templates. In some cases it's however
-useful to have multiple environments side by side, if different configurations
-are in use.
-
-The simplest way to configure Jinja2 to load templates for your application
-looks roughly like this::
-
- from jinja2 import Environment, PackageLoader
- env = Environment(loader=PackageLoader('yourapplication', 'templates'))
-
-This will create a template environment with the default settings and a
-loader that looks up the templates in the `templates` folder inside the
-`yourapplication` python package. Different loaders are available
-and you can also write your own if you want to load templates from a
-database or other resources.
-
-To load a template from this environment you just have to call the
-:meth:`get_template` method which then returns the loaded :class:`Template`::
-
- template = env.get_template('mytemplate.html')
-
-To render it with some variables, just call the :meth:`render` method::
-
- print template.render(the='variables', go='here')
-
-Using a template loader rather then passing strings to :class:`Template`
-or :meth:`Environment.from_string` has multiple advantages. Besides being
-a lot easier to use it also enables template inheritance.
-
-
-Unicode
--------
-
-Jinja2 is using Unicode internally which means that you have to pass Unicode
-objects to the render function or bytestrings that only consist of ASCII
-characters. Additionally newlines are normalized to one end of line
-sequence which is per default UNIX style (``\n``).
-
-Python 2.x supports two ways of representing string objects. One is the
-`str` type and the other is the `unicode` type, both of which extend a type
-called `basestring`. Unfortunately the default is `str` which should not
-be used to store text based information unless only ASCII characters are
-used. With Python 2.6 it is possible to make `unicode` the default on a per
-module level and with Python 3 it will be the default.
-
-To explicitly use a Unicode string you have to prefix the string literal
-with a `u`: ``u'Hänsel und Gretel sagen Hallo'``. That way Python will
-store the string as Unicode by decoding the string with the character
-encoding from the current Python module. If no encoding is specified this
-defaults to 'ASCII' which means that you can't use any non ASCII identifier.
-
-To set a better module encoding add the following comment to the first or
-second line of the Python module using the Unicode literal::
-
- # -*- coding: utf-8 -*-
-
-We recommend utf-8 as Encoding for Python modules and templates as it's
-possible to represent every Unicode character in utf-8 and because it's
-backwards compatible to ASCII. For Jinja2 the default encoding of templates
-is assumed to be utf-8.
-
-It is not possible to use Jinja2 to process non-Unicode data. The reason
-for this is that Jinja2 uses Unicode already on the language level. For
-example Jinja2 treats the non-breaking space as valid whitespace inside
-expressions which requires knowledge of the encoding or operating on an
-Unicode string.
-
-For more details about Unicode in Python have a look at the excellent
-`Unicode documentation`_.
-
-Another important thing is how Jinja2 is handling string literals in
-templates. A naive implementation would be using Unicode strings for
-all string literals but it turned out in the past that this is problematic
-as some libraries are typechecking against `str` explicitly. For example
-`datetime.strftime` does not accept Unicode arguments. To not break it
-completely Jinja2 is returning `str` for strings that fit into ASCII and
-for everything else `unicode`:
-
->>> m = Template(u"{% set a, b = 'foo', 'föö' %}").module
->>> m.a
-'foo'
->>> m.b
-u'f\xf6\xf6'
-
-
-.. _Unicode documentation: http://docs.python.org/dev/howto/unicode.html
-
-High Level API
---------------
-
-The high-level API is the API you will use in the application to load and
-render Jinja2 templates. The :ref:`low-level-api` on the other side is only
-useful if you want to dig deeper into Jinja2 or :ref:`develop extensions
-<jinja-extensions>`.
-
-.. autoclass:: Environment([options])
- :members: from_string, get_template, select_template,
- get_or_select_template, join_path, extend, compile_expression
-
- .. attribute:: shared
-
- If a template was created by using the :class:`Template` constructor
- an environment is created automatically. These environments are
- created as shared environments which means that multiple templates
- may have the same anonymous environment. For all shared environments
- this attribute is `True`, else `False`.
-
- .. attribute:: sandboxed
-
- If the environment is sandboxed this attribute is `True`. For the
- sandbox mode have a look at the documentation for the
- :class:`~jinja2.sandbox.SandboxedEnvironment`.
-
- .. attribute:: filters
-
- A dict of filters for this environment. As long as no template was
- loaded it's safe to add new filters or remove old. For custom filters
- see :ref:`writing-filters`. For valid filter names have a look at
- :ref:`identifier-naming`.
-
- .. attribute:: tests
-
- A dict of test functions for this environment. As long as no
- template was loaded it's safe to modify this dict. For custom tests
- see :ref:`writing-tests`. For valid test names have a look at
- :ref:`identifier-naming`.
-
- .. attribute:: globals
-
- A dict of global variables. These variables are always available
- in a template. As long as no template was loaded it's safe
- to modify this dict. For more details see :ref:`global-namespace`.
- For valid object names have a look at :ref:`identifier-naming`.
-
- .. automethod:: overlay([options])
-
- .. method:: undefined([hint, obj, name, exc])
-
- Creates a new :class:`Undefined` object for `name`. This is useful
- for filters or functions that may return undefined objects for
- some operations. All parameters except of `hint` should be provided
- as keyword parameters for better readability. The `hint` is used as
- error message for the exception if provided, otherwise the error
- message will be generated from `obj` and `name` automatically. The exception
- provided as `exc` is raised if something with the generated undefined
- object is done that the undefined object does not allow. The default
- exception is :exc:`UndefinedError`. If a `hint` is provided the
- `name` may be ommited.
-
- The most common way to create an undefined object is by providing
- a name only::
-
- return environment.undefined(name='some_name')
-
- This means that the name `some_name` is not defined. If the name
- was from an attribute of an object it makes sense to tell the
- undefined object the holder object to improve the error message::
-
- if not hasattr(obj, 'attr'):
- return environment.undefined(obj=obj, name='attr')
-
- For a more complex example you can provide a hint. For example
- the :func:`first` filter creates an undefined object that way::
-
- return environment.undefined('no first item, sequence was empty')
-
- If it the `name` or `obj` is known (for example because an attribute
- was accessed) it shold be passed to the undefined object, even if
- a custom `hint` is provided. This gives undefined objects the
- possibility to enhance the error message.
-
-.. autoclass:: Template
- :members: module, make_module
-
- .. attribute:: globals
-
- The dict with the globals of that template. It's unsafe to modify
- this dict as it may be shared with other templates or the environment
- that loaded the template.
-
- .. attribute:: name
-
- The loading name of the template. If the template was loaded from a
- string this is `None`.
-
- .. attribute:: filename
-
- The filename of the template on the file system if it was loaded from
- there. Otherwise this is `None`.
-
- .. automethod:: render([context])
-
- .. automethod:: generate([context])
-
- .. automethod:: stream([context])
-
-
-.. autoclass:: jinja2.environment.TemplateStream()
- :members: disable_buffering, enable_buffering, dump
-
-
-.. _identifier-naming:
-
-Notes on Identifiers
---------------------
-
-Jinja2 uses the regular Python 2.x naming rules. Valid identifiers have to
-match ``[a-zA-Z_][a-zA-Z0-9_]*``. As a matter of fact non ASCII characters
-are currently not allowed. This limitation will probably go away as soon as
-unicode identifiers are fully specified for Python 3.
-
-Filters and tests are looked up in separate namespaces and have slightly
-modified identifier syntax. Filters and tests may contain dots to group
-filters and tests by topic. For example it's perfectly valid to add a
-function into the filter dict and call it `to.unicode`. The regular
-expression for filter and test identifiers is
-``[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*```.
-
-
-Undefined Types
----------------
-
-These classes can be used as undefined types. The :class:`Environment`
-constructor takes an `undefined` parameter that can be one of those classes
-or a custom subclass of :class:`Undefined`. Whenever the template engine is
-unable to look up a name or access an attribute one of those objects is
-created and returned. Some operations on undefined values are then allowed,
-others fail.
-
-The closest to regular Python behavior is the `StrictUndefined` which
-disallows all operations beside testing if it's an undefined object.
-
-.. autoclass:: jinja2.Undefined()
-
- .. attribute:: _undefined_hint
-
- Either `None` or an unicode string with the error message for
- the undefined object.
-
- .. attribute:: _undefined_obj
-
- Either `None` or the owner object that caused the undefined object
- to be created (for example because an attribute does not exist).
-
- .. attribute:: _undefined_name
-
- The name for the undefined variable / attribute or just `None`
- if no such information exists.
-
- .. attribute:: _undefined_exception
-
- The exception that the undefined object wants to raise. This
- is usually one of :exc:`UndefinedError` or :exc:`SecurityError`.
-
- .. method:: _fail_with_undefined_error(\*args, \**kwargs)
-
- When called with any arguments this method raises
- :attr:`_undefined_exception` with an error message generated
- from the undefined hints stored on the undefined object.
-
-.. autoclass:: jinja2.DebugUndefined()
-
-.. autoclass:: jinja2.StrictUndefined()
-
-Undefined objects are created by calling :attr:`undefined`.
-
-.. admonition:: Implementation
-
- :class:`Undefined` objects are implemented by overriding the special
- `__underscore__` methods. For example the default :class:`Undefined`
- class implements `__unicode__` in a way that it returns an empty
- string, however `__int__` and others still fail with an exception. To
- allow conversion to int by returning ``0`` you can implement your own::
-
- class NullUndefined(Undefined):
- def __int__(self):
- return 0
- def __float__(self):
- return 0.0
-
- To disallow a method, just override it and raise
- :attr:`~Undefined._undefined_exception`. Because this is a very common
- idom in undefined objects there is the helper method
- :meth:`~Undefined._fail_with_undefined_error` that does the error raising
- automatically. Here a class that works like the regular :class:`Undefined`
- but chokes on iteration::
-
- class NonIterableUndefined(Undefined):
- __iter__ = Undefined._fail_with_undefined_error
-
-
-The Context
------------
-
-.. autoclass:: jinja2.runtime.Context()
- :members: resolve, get_exported, get_all
-
- .. attribute:: parent
-
- A dict of read only, global variables the template looks up. These
- can either come from another :class:`Context`, from the
- :attr:`Environment.globals` or :attr:`Template.globals` or points
- to a dict created by combining the globals with the variables
- passed to the render function. It must not be altered.
-
- .. attribute:: vars
-
- The template local variables. This list contains environment and
- context functions from the :attr:`parent` scope as well as local
- modifications and exported variables from the template. The template
- will modify this dict during template evaluation but filters and
- context functions are not allowed to modify it.
-
- .. attribute:: environment
-
- The environment that loaded the template.
-
- .. attribute:: exported_vars
-
- This set contains all the names the template exports. The values for
- the names are in the :attr:`vars` dict. In order to get a copy of the
- exported variables as dict, :meth:`get_exported` can be used.
-
- .. attribute:: name
-
- The load name of the template owning this context.
-
- .. attribute:: blocks
-
- A dict with the current mapping of blocks in the template. The keys
- in this dict are the names of the blocks, and the values a list of
- blocks registered. The last item in each list is the current active
- block (latest in the inheritance chain).
-
- .. automethod:: jinja2.runtime.Context.call(callable, \*args, \**kwargs)
-
-
-.. admonition:: Implementation
-
- Context is immutable for the same reason Python's frame locals are
- immutable inside functions. Both Jinja2 and Python are not using the
- context / frame locals as data storage for variables but only as primary
- data source.
-
- When a template accesses a variable the template does not define, Jinja2
- looks up the variable in the context, after that the variable is treated
- as if it was defined in the template.
-
-
-.. _loaders:
-
-Loaders
--------
-
-Loaders are responsible for loading templates from a resource such as the
-file system. The environment will keep the compiled modules in memory like
-Python's `sys.modules`. Unlike `sys.modules` however this cache is limited in
-size by default and templates are automatically reloaded.
-All loaders are subclasses of :class:`BaseLoader`. If you want to create your
-own loader, subclass :class:`BaseLoader` and override `get_source`.
-
-.. autoclass:: jinja2.BaseLoader
- :members: get_source, load
-
-Here a list of the builtin loaders Jinja2 provides:
-
-.. autoclass:: jinja2.FileSystemLoader
-
-.. autoclass:: jinja2.PackageLoader
-
-.. autoclass:: jinja2.DictLoader
-
-.. autoclass:: jinja2.FunctionLoader
-
-.. autoclass:: jinja2.PrefixLoader
-
-.. autoclass:: jinja2.ChoiceLoader
-
-
-.. _bytecode-cache:
-
-Bytecode Cache
---------------
-
-Jinja 2.1 and higher support external bytecode caching. Bytecode caches make
-it possible to store the generated bytecode on the file system or a different
-location to avoid parsing the templates on first use.
-
-This is especially useful if you have a web application that is initialized on
-the first request and Jinja compiles many templates at once which slows down
-the application.
-
-To use a bytecode cache, instanciate it and pass it to the :class:`Environment`.
-
-.. autoclass:: jinja2.BytecodeCache
- :members: load_bytecode, dump_bytecode, clear
-
-.. autoclass:: jinja2.bccache.Bucket
- :members: write_bytecode, load_bytecode, bytecode_from_string,
- bytecode_to_string, reset
-
- .. attribute:: environment
-
- The :class:`Environment` that created the bucket.
-
- .. attribute:: key
-
- The unique cache key for this bucket
-
- .. attribute:: code
-
- The bytecode if it's loaded, otherwise `None`.
-
-
-Builtin bytecode caches:
-
-.. autoclass:: jinja2.FileSystemBytecodeCache
-
-.. autoclass:: jinja2.MemcachedBytecodeCache
-
-
-Utilities
----------
-
-These helper functions and classes are useful if you add custom filters or
-functions to a Jinja2 environment.
-
-.. autofunction:: jinja2.environmentfilter
-
-.. autofunction:: jinja2.contextfilter
-
-.. autofunction:: jinja2.environmentfunction
-
-.. autofunction:: jinja2.contextfunction
-
-.. function:: escape(s)
-
- Convert the characters ``&``, ``<``, ``>``, ``'``, and ``"`` in string `s`
- to HTML-safe sequences. Use this if you need to display text that might
- contain such characters in HTML. This function will not escaped objects
- that do have an HTML representation such as already escaped data.
-
- The return value is a :class:`Markup` string.
-
-.. autofunction:: jinja2.clear_caches
-
-.. autofunction:: jinja2.is_undefined
-
-.. autoclass:: jinja2.Markup([string])
- :members: escape, unescape, striptags
-
-.. admonition:: Note
-
- The Jinja2 :class:`Markup` class is compatible with at least Pylons and
- Genshi. It's expected that more template engines and framework will pick
- up the `__html__` concept soon.
-
-
-Exceptions
-----------
-
-.. autoexception:: jinja2.TemplateError
-
-.. autoexception:: jinja2.UndefinedError
-
-.. autoexception:: jinja2.TemplateNotFound
-
-.. autoexception:: jinja2.TemplatesNotFound
-
-.. autoexception:: jinja2.TemplateSyntaxError
-
- .. attribute:: message
-
- The error message as utf-8 bytestring.
-
- .. attribute:: lineno
-
- The line number where the error occurred
-
- .. attribute:: name
-
- The load name for the template as unicode string.
-
- .. attribute:: filename
-
- The filename that loaded the template as bytestring in the encoding
- of the file system (most likely utf-8 or mbcs on Windows systems).
-
- The reason why the filename and error message are bytestrings and not
- unicode strings is that Python 2.x is not using unicode for exceptions
- and tracebacks as well as the compiler. This will change with Python 3.
-
-.. autoexception:: jinja2.TemplateAssertionError
-
-
-.. _writing-filters:
-
-Custom Filters
---------------
-
-Custom filters are just regular Python functions that take the left side of
-the filter as first argument and the the arguments passed to the filter as
-extra arguments or keyword arguments.
-
-For example in the filter ``{{ 42|myfilter(23) }}`` the function would be
-called with ``myfilter(42, 23)``. Here for example a simple filter that can
-be applied to datetime objects to format them::
-
- def datetimeformat(value, format='%H:%M / %d-%m-%Y'):
- return value.strftime(format)
-
-You can register it on the template environment by updating the
-:attr:`~Environment.filters` dict on the environment::
-
- environment.filters['datetimeformat'] = datetimeformat
-
-Inside the template it can then be used as follows:
-
-.. sourcecode:: jinja
-
- written on: {{ article.pub_date|datetimeformat }}
- publication date: {{ article.pub_date|datetimeformat('%d-%m-%Y') }}
-
-Filters can also be passed the current template context or environment. This
-is useful if a filter wants to return an undefined value or check the current
-:attr:`~Environment.autoescape` setting. For this purpose two decorators
-exist: :func:`environmentfilter` and :func:`contextfilter`.
-
-Here a small example filter that breaks a text into HTML line breaks and
-paragraphs and marks the return value as safe HTML string if autoescaping is
-enabled::
-
- import re
- from jinja2 import environmentfilter, Markup, escape
-
- _paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')
-
- @environmentfilter
- def nl2br(environment, value):
- result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', '<br>\n')
- for p in _paragraph_re.split(escape(value)))
- if environment.autoescape:
- result = Markup(result)
- return result
-
-Context filters work the same just that the first argument is the current
-active :class:`Context` rather then the environment.
-
-
-.. _writing-tests:
-
-Custom Tests
-------------
-
-Tests work like filters just that there is no way for a test to get access
-to the environment or context and that they can't be chained. The return
-value of a test should be `True` or `False`. The purpose of a test is to
-give the template designers the possibility to perform type and conformability
-checks.
-
-Here a simple test that checks if a variable is a prime number::
-
- import math
-
- def is_prime(n):
- if n == 2:
- return True
- for i in xrange(2, int(math.ceil(math.sqrt(n))) + 1):
- if n % i == 0:
- return False
- return True
-
-
-You can register it on the template environment by updating the
-:attr:`~Environment.tests` dict on the environment::
-
- environment.tests['prime'] = is_prime
-
-A template designer can then use the test like this:
-
-.. sourcecode:: jinja
-
- {% if 42 is prime %}
- 42 is a prime number
- {% else %}
- 42 is not a prime number
- {% endif %}
-
-
-.. _global-namespace:
-
-The Global Namespace
---------------------
-
-Variables stored in the :attr:`Environment.globals` dict are special as they
-are available for imported templates too, even if they are imported without
-context. This is the place where you can put variables and functions
-that should be available all the time. Additionally :attr:`Template.globals`
-exist that are variables available to a specific template that are available
-to all :meth:`~Template.render` calls.
-
-
-.. _low-level-api:
-
-Low Level API
--------------
-
-The low level API exposes functionality that can be useful to understand some
-implementation details, debugging purposes or advanced :ref:`extension
-<jinja-extensions>` techniques. Unless you know exactly what you are doing we
-don't recommend using any of those.
-
-.. automethod:: Environment.lex
-
-.. automethod:: Environment.parse
-
-.. automethod:: Environment.preprocess
-
-.. automethod:: Template.new_context
-
-.. method:: Template.root_render_func(context)
-
- This is the low level render function. It's passed a :class:`Context`
- that has to be created by :meth:`new_context` of the same template or
- a compatible template. This render function is generated by the
- compiler from the template code and returns a generator that yields
- unicode strings.
-
- If an exception in the template code happens the template engine will
- not rewrite the exception but pass through the original one. As a
- matter of fact this function should only be called from within a
- :meth:`render` / :meth:`generate` / :meth:`stream` call.
-
-.. attribute:: Template.blocks
-
- A dict of block render functions. Each of these functions works exactly
- like the :meth:`root_render_func` with the same limitations.
-
-.. attribute:: Template.is_up_to_date
-
- This attribute is `False` if there is a newer version of the template
- available, otherwise `True`.
-
-.. admonition:: Note
-
- The low-level API is fragile. Future Jinja2 versions will try not to
- change it in a backwards incompatible way but modifications in the Jinja2
- core may shine through. For example if Jinja2 introduces a new AST node
- in later versions that may be returned by :meth:`~Environment.parse`.
-
-The Meta API
-------------
-
-.. versionadded:: 2.2
-
-The meta API returns some information about abstract syntax trees that
-could help applications to implement more advanced template concepts. All
-the functions of the meta API operate on an abstract syntax tree as
-returned by the :meth:`Environment.parse` method.
-
-.. autofunction:: jinja2.meta.find_undeclared_variables
-
-.. autofunction:: jinja2.meta.find_referenced_templates
--- a/bundled/jinja2/docs/cache_extension.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-from jinja2 import nodes
-from jinja2.ext import Extension
-
-
-class FragmentCacheExtension(Extension):
- # a set of names that trigger the extension.
- tags = set(['cache'])
-
- def __init__(self, environment):
- super(FragmentCacheExtension, self).__init__(environment)
-
- # add the defaults to the environment
- environment.extend(
- fragment_cache_prefix='',
- fragment_cache=None
- )
-
- def parse(self, parser):
- # the first token is the token that started the tag. In our case
- # we only listen to ``'cache'`` so this will be a name token with
- # `cache` as value. We get the line number so that we can give
- # that line number to the nodes we create by hand.
- lineno = parser.stream.next().lineno
-
- # now we parse a single expression that is used as cache key.
- args = [parser.parse_expression()]
-
- # if there is a comma, the user provided a timeout. If not use
- # None as second parameter.
- if parser.stream.skip_if('comma'):
- args.append(parser.parse_expression())
- else:
- args.append(nodes.Const(None))
-
- # now we parse the body of the cache block up to `endcache` and
- # drop the needle (which would always be `endcache` in that case)
- body = parser.parse_statements(['name:endcache'], drop_needle=True)
-
- # now return a `CallBlock` node that calls our _cache_support
- # helper method on this extension.
- return nodes.CallBlock(self.call_method('_cache_support', args),
- [], [], body).set_lineno(lineno)
-
- def _cache_support(self, name, timeout, caller):
- """Helper callback."""
- key = self.environment.fragment_cache_prefix + name
-
- # try to load the block from the cache
- # if there is no fragment in the cache, render it and store
- # it in the cache.
- rv = self.environment.fragment_cache.get(key)
- if rv is not None:
- return rv
- rv = caller()
- self.environment.fragment_cache.add(key, rv, timeout)
- return rv
--- a/bundled/jinja2/docs/changelog.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-.. module:: jinja2
-
-.. include:: ../CHANGES
--- a/bundled/jinja2/docs/conf.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Jinja2 documentation build configuration file, created by
-# sphinx-quickstart on Sun Apr 27 21:42:41 2008.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# The contents of this file are pickled, so don't put values in the namespace
-# that aren't pickleable (module imports are okay, they're removed automatically).
-#
-# All configuration values have a default value; values that are commented out
-# serve to show the default value.
-
-import sys, os
-
-# If your extensions are in another directory, add it here. If the directory
-# is relative to the documentation root, use os.path.abspath to make it
-# absolute, like shown here.
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-
-# General configuration
-# ---------------------
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'jinjaext']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General substitutions.
-project = 'Jinja2'
-copyright = '2008, Armin Ronacher'
-
-# The default replacements for |version| and |release|, also used in various
-# other places throughout the built documents.
-#
-# The short X.Y version.
-version = '2.0'
-# The full version, including alpha/beta/rc tags.
-release = '2.0'
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-today_fmt = '%B %d, %Y'
-
-# List of documents that shouldn't be included in the build.
-#unused_docs = []
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'jinjaext.JinjaStyle'
-
-
-# Options for HTML output
-# -----------------------
-
-# The style sheet to use for HTML and HTML Help pages. A file of that name
-# must exist either in Sphinx' static/ path, or in one of the custom paths
-# given in html_static_path.
-html_style = 'style.css'
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# no modindex
-html_use_modindex = False
-
-# If true, the reST sources are included in the HTML build as _sources/<name>.
-#html_copy_source = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it.
-#html_use_opensearch = False
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'Jinja2doc'
-
-
-# Options for LaTeX output
-# ------------------------
-
-# The paper size ('letter' or 'a4').
-latex_paper_size = 'a4'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, document class [howto/manual]).
-latex_documents = [
- ('index', 'Jinja2.tex', 'Jinja2 Documentation', 'Armin Ronacher', 'manual', 'toctree_only'),
-]
-
-# Additional stuff for the LaTeX preamble.
-latex_preamble = '''
-\usepackage{palatino}
-\definecolor{TitleColor}{rgb}{0.7,0,0}
-\definecolor{InnerLinkColor}{rgb}{0.7,0,0}
-\definecolor{OuterLinkColor}{rgb}{0.8,0,0}
-\definecolor{VerbatimColor}{rgb}{0.985,0.985,0.985}
-\definecolor{VerbatimBorderColor}{rgb}{0.8,0.8,0.8}
-'''
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-latex_use_modindex = False
--- a/bundled/jinja2/docs/extensions.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,268 +0,0 @@
-.. _jinja-extensions:
-
-Extensions
-==========
-
-Jinja2 supports extensions that can add extra filters, tests, globals or even
-extend the parser. The main motivation of extensions is it to move often used
-code into a reusable class like adding support for internationalization.
-
-
-Adding Extensions
------------------
-
-Extensions are added to the Jinja2 environment at creation time. Once the
-environment is created additional extensions cannot be added. To add an
-extension pass a list of extension classes or import paths to the
-`environment` parameter of the :class:`Environment` constructor. The following
-example creates a Jinja2 environment with the i18n extension loaded::
-
- jinja_env = Environment(extensions=['jinja2.ext.i18n'])
-
-
-.. _i18n-extension:
-
-i18n Extension
---------------
-
-**Import name:** `jinja2.ext.i18n`
-
-Jinja2 currently comes with one extension, the i18n extension. It can be
-used in combination with `gettext`_ or `babel`_. If the i18n extension is
-enabled Jinja2 provides a `trans` statement that marks the wrapped string as
-translatable and calls `gettext`.
-
-After enabling dummy `_` function that forwards calls to `gettext` is added
-to the environment globals. An internationalized application then has to
-provide at least an `gettext` and optoinally a `ngettext` function into the
-namespace. Either globally or for each rendering.
-
-After enabling of the extension the environment provides the following
-additional methods:
-
-.. method:: jinja2.Environment.install_gettext_translations(translations)
-
- Installs a translation globally for that environment. The tranlations
- object provided must implement at least `ugettext` and `ungettext`.
- The `gettext.NullTranslations` and `gettext.GNUTranslations` classes
- as well as `Babel`_\s `Translations` class are supported.
-
-.. method:: jinja2.Environment.install_null_translations()
-
- Install dummy gettext functions. This is useful if you want to prepare
- the application for internationalization but don't want to implement the
- full internationalization system yet.
-
-.. method:: jinja2.Environment.uninstall_gettext_translations()
-
- Uninstall the translations again.
-
-.. method:: jinja2.Environment.extract_translations(source)
-
- Extract localizable strings from the given template node or source.
-
- For every string found this function yields a ``(lineno, function,
- message)`` tuple, where:
-
- * `lineno` is the number of the line on which the string was found,
- * `function` is the name of the `gettext` function used (if the
- string was extracted from embedded Python code), and
- * `message` is the string itself (a `unicode` object, or a tuple
- of `unicode` objects for functions with multiple string arguments).
-
- If `Babel`_ is installed :ref:`the babel integration <babel-integration>`
- can be used to extract strings for babel.
-
-For a web application that is available in multiple languages but gives all
-the users the same language (for example a multilingual forum software
-installed for a French community) may load the translations once and add the
-translation methods to the environment at environment generation time::
-
- translations = get_gettext_translations()
- env = Environment(extensions=['jinja2.ext.i18n'])
- env.install_gettext_translations(translations)
-
-The `get_gettext_translations` function would return the translator for the
-current configuration. (For example by using `gettext.find`)
-
-The usage of the `i18n` extension for template designers is covered as part
-:ref:`of the template documentation <i18n-in-templates>`.
-
-.. _gettext: http://docs.python.org/dev/library/gettext
-.. _Babel: http://babel.edgewall.org/
-
-
-Expression Statement
---------------------
-
-**Import name:** `jinja2.ext.do`
-
-The "do" aka expression-statement extension adds a simple `do` tag to the
-template engine that works like a variable expression but ignores the
-return value.
-
-.. _loopcontrols-extension:
-
-Loop Controls
--------------
-
-**Import name:** `jinja2.ext.loopcontrols`
-
-This extension adds support for `break` and `continue` in loops. After
-enabling Jinja2 provides those two keywords which work exactly like in
-Python.
-
-.. _with-extension:
-
-With Statement
---------------
-
-**Import name:** `jinja2.ext.with_`
-
-.. versionadded:: 2.3
-
-This extension adds support for the with keyword. Using this keyword it
-is possible to enforce a nested scope in a template. Variables can be
-declared directly in the opening block of the with statement or using a
-standard `set` statement directly within.
-
-
-.. _writing-extensions:
-
-Writing Extensions
-------------------
-
-.. module:: jinja2.ext
-
-By writing extensions you can add custom tags to Jinja2. This is a non trival
-task and usually not needed as the default tags and expressions cover all
-common use cases. The i18n extension is a good example of why extensions are
-useful, another one would be fragment caching.
-
-When writing extensions you have to keep in mind that you are working with the
-Jinja2 template compiler which does not validate the node tree you are possing
-to it. If the AST is malformed you will get all kinds of compiler or runtime
-errors that are horrible to debug. Always make sure you are using the nodes
-you create correctly. The API documentation below shows which nodes exist and
-how to use them.
-
-Example Extension
-~~~~~~~~~~~~~~~~~
-
-The following example implements a `cache` tag for Jinja2 by using the
-`Werkzeug`_ caching contrib module:
-
-.. literalinclude:: cache_extension.py
- :language: python
-
-And here is how you use it in an environment::
-
- from jinja2 import Environment
- from werkzeug.contrib.cache import SimpleCache
-
- env = Environment(extensions=[FragmentCacheExtension])
- env.fragment_cache = SimpleCache()
-
-Inside the template it's then possible to mark blocks as cacheable. The
-following example caches a sidebar for 300 seconds:
-
-.. sourcecode:: html+jinja
-
- {% cache 'sidebar', 300 %}
- <div class="sidebar">
- ...
- </div>
- {% endcache %}
-
-.. _Werkzeug: http://werkzeug.pocoo.org/
-
-Extension API
-~~~~~~~~~~~~~
-
-Extensions always have to extend the :class:`jinja2.ext.Extension` class:
-
-.. autoclass:: Extension
- :members: preprocess, filter_stream, parse, attr, call_method
-
- .. attribute:: identifier
-
- The identifier of the extension. This is always the true import name
- of the extension class and must not be changed.
-
- .. attribute:: tags
-
- If the extension implements custom tags this is a set of tag names
- the extension is listening for.
-
-Parser API
-~~~~~~~~~~
-
-The parser passed to :meth:`Extension.parse` provides ways to parse
-expressions of different types. The following methods may be used by
-extensions:
-
-.. autoclass:: jinja2.parser.Parser
- :members: parse_expression, parse_tuple, parse_assign_target,
- parse_statements, free_identifier, fail
-
- .. attribute:: filename
-
- The filename of the template the parser processes. This is **not**
- the load name of the template. For the load name see :attr:`name`.
- For templates that were not loaded form the file system this is
- `None`.
-
- .. attribute:: name
-
- The load name of the template.
-
- .. attribute:: stream
-
- The current :class:`~jinja2.lexer.TokenStream`
-
-.. autoclass:: jinja2.lexer.TokenStream
- :members: push, look, eos, skip, next, next_if, skip_if, expect
-
- .. attribute:: current
-
- The current :class:`~jinja2.lexer.Token`.
-
-.. autoclass:: jinja2.lexer.Token
- :members: test, test_any
-
- .. attribute:: lineno
-
- The line number of the token
-
- .. attribute:: type
-
- The type of the token. This string is interned so you may compare
- it with arbitrary strings using the `is` operator.
-
- .. attribute:: value
-
- The value of the token.
-
-There is also a utility function in the lexer module that can count newline
-characters in strings:
-
-.. autofunction:: jinja2.lexer.count_newlines
-
-AST
-~~~
-
-The AST (Abstract Syntax Tree) is used to represent a template after parsing.
-It's build of nodes that the compiler then converts into executable Python
-code objects. Extensions that provide custom statements can return nodes to
-execute custom Python code.
-
-The list below describes all nodes that are currently available. The AST may
-change between Jinja2 versions but will stay backwards compatible.
-
-For more information have a look at the repr of :meth:`jinja2.Environment.parse`.
-
-.. module:: jinja2.nodes
-
-.. jinjanodes::
-
-.. autoexception:: Impossible
--- a/bundled/jinja2/docs/faq.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-Frequently Asked Questions
-==========================
-
-This page answers some of the often asked questions about Jinja.
-
-.. highlight:: html+jinja
-
-Why is it called Jinja?
------------------------
-
-The name Jinja was chosen because it's the name of a Japanese temple and
-temple and template share a similar pronunciation. It is not named after
-the capital city of Uganda.
-
-How fast is it?
----------------
-
-We really hate benchmarks especially since they don't reflect much. The
-performance of a template depends on many factors and you would have to
-benchmark different engines in different situations. The benchmarks from the
-testsuite show that Jinja2 has a similar performance to `Mako`_ and is between
-10 and 20 times faster than Django's template engine or Genshi. These numbers
-should be taken with tons of salt as the benchmarks that took these numbers
-only test a few performance related situations such as looping. Generally
-speaking the performance of a template engine doesn't matter much as the
-usual bottleneck in a web application is either the database or the application
-code.
-
-.. _Mako: http://www.makotemplates.org/
-
-How Compatible is Jinja2 with Django?
--------------------------------------
-
-The default syntax of Jinja2 matches Django syntax in many ways. However
-this similarity doesn't mean that you can use a Django template unmodified
-in Jinja2. For example filter arguments use a function call syntax rather
-than a colon to separate filter name and arguments. Additionally the
-extension interface in Jinja is fundamentally different from the Django one
-which means that your custom tags won't work any longer.
-
-Generally speaking you will use much less custom extensions as the Jinja
-template system allows you to use a certain subset of Python expressions
-which can replace most Django extensions. For example instead of using
-something like this::
-
- {% load comments %}
- {% get_latest_comments 10 as latest_comments %}
- {% for comment in latest_comments %}
- ...
- {% endfor %}
-
-You will most likely provide an object with attributes to retrieve
-comments from the database::
-
- {% for comment in models.comments.latest(10) %}
- ...
- {% endfor %}
-
-Or directly provide the model for quick testing::
-
- {% for comment in Comment.objects.order_by('-pub_date')[:10] %}
- ...
- {% endfor %}
-
-Please keep in mind that even though you may put such things into templates
-it still isn't a good idea. Queries should go into the view code and not
-the template!
-
-Isn't it a terrible idea to put Logic into Templates?
------------------------------------------------------
-
-Without a doubt you should try to remove as much logic from templates as
-possible. But templates without any logic mean that you have to do all
-the processing in the code which is boring and stupid. A template engine
-that does that is shipped with Python and called `string.Template`. Comes
-without loops and if conditions and is by far the fastest template engine
-you can get for Python.
-
-So some amount of logic is required in templates to keep everyone happy.
-And Jinja leaves it pretty much to you how much logic you want to put into
-templates. There are some restrictions in what you can do and what not.
-
-Jinja2 neither allows you to put arbitrary Python code into templates nor
-does it allow all Python expressions. The operators are limited to the
-most common ones and more advanced expressions such as list comprehensions
-and generator expressions are not supported. This keeps the template engine
-easier to maintain and templates more readable.
-
-Why is Autoescaping not the Default?
-------------------------------------
-
-There are multiple reasons why automatic escaping is not the default mode
-and also not the recommended one. While automatic escaping of variables
-means that you will less likely have an XSS problem it also causes a huge
-amount of extra processing in the template engine which can cause serious
-performance problems. As Python doesn't provide a way to mark strings as
-unsafe Jinja has to hack around that limitation by providing a custom
-string class (the :class:`Markup` string) that safely interacts with safe
-and unsafe strings.
-
-With explicit escaping however the template engine doesn't have to perform
-any safety checks on variables. Also a human knows not to escape integers
-or strings that may never contain characters one has to escape or already
-HTML markup. For example when iterating over a list over a table of
-integers and floats for a table of statistics the template designer can
-omit the escaping because he knows that integers or floats don't contain
-any unsafe parameters.
-
-Additionally Jinja2 is a general purpose template engine and not only used
-for HTML/XML generation. For example you may generate LaTeX, emails,
-CSS, JavaScript, or configuration files.
-
-Why is the Context immutable?
------------------------------
-
-When writing a :func:`contextfunction` or something similar you may have
-noticed that the context tries to stop you from modifying it. If you have
-managed to modify the context by using an internal context API you may
-have noticed that changes in the context don't seem to be visible in the
-template. The reason for this is that Jinja uses the context only as
-primary data source for template variables for performance reasons.
-
-If you want to modify the context write a function that returns a variable
-instead that one can assign to a variable by using set::
-
- {% set comments = get_latest_comments() %}
-
-I don't have the _speedups Module. Is Jinja slower now?
---------------------------------------------------------
-
-To achieve a good performance with automatic escaping enabled, the escaping
-function is also implemented in pure C and used if Jinja2 was installed with
-the speedups module. This happens automatically if a C compiler is available
-on the system during installation.
-
-My tracebacks look weird. What's happening?
---------------------------------------------
-
-If the speedups module is not compiled and you are using a Python installation
-without ctypes (Python 2.4 without ctypes, Jython or Google's AppEngine)
-Jinja2 is unable to provide correct debugging information and the traceback
-may be incomplete. There is currently no good workaround for Jython or
-the AppEngine as ctypes is unavailable there and it's not possible to use
-the speedups extension.
-
-Why is there no Python 2.3 support?
------------------------------------
-
-Python 2.3 is missing a lot of features that are used heavily in Jinja2. This
-decision was made as with the upcoming Python 2.6 and 3.0 versions it becomes
-harder to maintain the code for older Python versions. If you really need
-Python 2.3 support you either have to use `Jinja 1`_ or other templating
-engines that still support 2.3.
-
-My Macros are overriden by something
-------------------------------------
-
-In some situations the Jinja scoping appears arbitrary:
-
-layout.tmpl:
-
-.. sourcecode:: jinja
-
- {% macro foo() %}LAYOUT{% endmacro %}
- {% block body %}{% endblock %}
-
-child.tmpl:
-
-.. sourcecode:: jinja
-
- {% extends 'layout.tmpl' %}
- {% macro foo() %}CHILD{% endmacro %}
- {% block body %}{{ foo() }}{% endblock %}
-
-This will print ``LAYOUT`` in Jinja2. This is a side effect of having
-the parent template evaluated after the child one. This allows child
-templates passing information to the parent template. To avoid this
-issue rename the macro or variable in the parent template to have an
-uncommon prefix.
-
-.. _Jinja 1: http://jinja.pocoo.org/1/
--- a/bundled/jinja2/docs/index.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-Jinja2 Documentation
-====================
-
-This is the documentation for the Jinja2 general purpose templating language.
-Jinja2 is a library for Python 2.4 and onwards that is designed to be flexible,
-fast and secure.
-
-.. toctree::
- :maxdepth: 2
-
- intro
- api
- sandbox
- templates
- extensions
- integration
- switching
- tricks
-
- faq
- changelog
-
-If you can't find the information you're looking for, have a look at the
-index of try to find it using the search function:
-
-* :ref:`genindex`
-* :ref:`search`
--- a/bundled/jinja2/docs/integration.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-Integration
-===========
-
-Jinja2 provides some code for integration into other tools such as frameworks,
-the `Babel`_ library or your favourite editor for fancy code highlighting.
-This is a brief description of whats included.
-
-.. _babel-integration:
-
-Babel Integration
------------------
-
-Jinja provides support for extracting gettext messages from templates via a
-`Babel`_ extractor entry point called `jinja2.ext.babel_extract`. The Babel
-support is implemented as part of the :ref:`i18n-extension` extension.
-
-Gettext messages extracted from both `trans` tags and code expressions.
-
-To extract gettext messages from templates, the project needs a Jinja2 section
-in its Babel extraction method `mapping file`_:
-
-.. sourcecode:: ini
-
- [jinja2: **/templates/**.html]
- encoding = utf-8
-
-The syntax related options of the :class:`Environment` are also available as
-configuration values in the mapping file. For example to tell the extraction
-that templates use ``%`` as `line_statement_prefix` you can use this code:
-
-.. sourcecode:: ini
-
- [jinja2: **/templates/**.html]
- encoding = utf-8
- line_statement_prefix = %
-
-:ref:`jinja-extensions` may also be defined by passing a comma separated list
-of import paths as `extensions` value. The i18n extension is added
-automatically.
-
-.. _mapping file: http://babel.edgewall.org/wiki/Documentation/messages.html#extraction-method-mapping-and-configuration
-
-Pylons
-------
-
-With `Pylons`_ 0.9.7 onwards it's incredible easy to integrate Jinja into a
-Pylons powered application.
-
-The template engine is configured in `config/environment.py`. The configuration
-for Jinja2 looks something like that::
-
- from jinja2 import Environment, PackageLoader
- config['pylons.app_globals'].jinja_env = Environment(
- loader=PackageLoader('yourapplication', 'templates')
- )
-
-After that you can render Jinja templates by using the `render_jinja` function
-from the `pylons.templating` module.
-
-Additionally it's a good idea to set the Pylons' `c` object into strict mode.
-Per default any attribute to not existing attributes on the `c` object return
-an empty string and not an undefined object. To change this just use this
-snippet and add it into your `config/environment.py`::
-
- config['pylons.strict_c'] = True
-
-.. _Pylons: http://www.pylonshq.com/
-
-TextMate
---------
-
-Inside the `ext` folder of Jinja2 there is a bundle for TextMate that supports
-syntax highlighting for Jinja1 and Jinja2 for text based templates as well as
-HTML. It also contains a few often used snippets.
-
-Vim
----
-
-A syntax plugin for `Vim`_ exists in the Vim-scripts directory as well as the
-ext folder of Jinja2. `The script <http://www.vim.org/scripts/script.php?script_id=1856>`_
-supports Jinja1 and Jinja2. Once installed two file types are available `jinja`
-and `htmljinja`. The first one for text based templates, the latter for HTML
-templates.
-
-Copy the files into your `syntax` folder.
-
-.. _Babel: http://babel.edgewall.org/
-.. _Vim: http://www.vim.org/
--- a/bundled/jinja2/docs/intro.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-Introduction
-============
-
-This is the documentation for the Jinja2 general purpose templating language.
-Jinja2 is a library for Python 2.4 and onwards that is designed to be flexible,
-fast and secure.
-
-If you have any exposure to other text-based template languages, such as Smarty or
-Django, you should feel right at home with Jinja2. It's both designer and
-developer friendly by sticking to Python's principles and adding functionality
-useful for templating environments.
-
-The key-features are...
-
-- ... **configurable syntax**. If you are generating LaTeX or other formats
- with Jinja2 you can change the delimiters to something that integrates better
- into the LaTeX markup.
-
-- ... **fast**. While performance is not the primarily target of Jinja2 it's
- surprisingly fast. The overhead compared to regular Python code was reduced
- to the very minimum.
-
-- ... **easy to debug**. Jinja2 integrates directly into the python traceback
- system which allows you to debug Jinja2 templates with regular python
- debugging helpers.
-
-- ... **secure**. It's possible to evaluate untrusted template code if the
- optional sandbox is enabled. This allows Jinja2 to be used as templating
- language for applications where users may modify the template design.
-
-
-Prerequisites
--------------
-
-Jinja2 needs at least **Python 2.4** to run. Additionally a working C-compiler
-that can create python extensions should be installed for the debugger. If no
-C-compiler is available and you are using Python 2.4 the `ctypes`_ module
-should be installed.
-
-If you don't have a working C-compiler and you are trying to install the source
-release with the speedups you will get a compiler error. This however can be
-circumvented by passing the ``--without-speedups`` command line argument to the
-setup script::
-
- $ python setup.py --with-speedups install
-
-(As of Jinja 2.2, the speedups are disabled by default and can be enabled
-with ``--with-speedups``. See :ref:`enable-speedups`)
-
-.. _ctypes: http://python.net/crew/theller/ctypes/
-
-
-Installation
-------------
-
-You have multiple ways to install Jinja2. If you are unsure what to do, go
-with the Python egg or tarball.
-
-As a Python egg (via easy_install)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can install the most recent Jinja2 version using `easy_install`_ or `pip`_::
-
- easy_install Jinja2
- pip install Jinja2
-
-This will install a Jinja2 egg in your Python installation's site-packages
-directory.
-
-(If you are installing from the windows command line omit the `sudo` and make
-sure to run the command as user with administrator rights)
-
-From the tarball release
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Download the most recent tarball from the `download page`_
-2. Unpack the tarball
-3. ``sudo python setup.py install``
-
-Note that you either have to have setuptools or `distribute`_ installed,
-the latter is preferred.
-
-This will install Jinja2 into your Python installation's site-packages directory.
-
-.. _distribute: http://pypi.python.org/pypi/distribute
-
-Installing the development version
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-1. Install `mercurial`_
-2. ``hg clone http://dev.pocoo.org/hg/jinja2-main jinja2``
-3. ``cd jinja2``
-4. ``ln -s jinja2 /usr/lib/python2.X/site-packages``
-
-As an alternative to steps 4 you can also do ``python setup.py develop``
-which will install the package via distribute in development mode. This also
-has the advantage that the C extensions are compiled.
-
-Alternative you can use `pip`_ to install the current development
-snapshot::
-
- sudo pip install Jinja2==dev
-
-Or the `easy_install`_ command::
-
- sudo easy_install Jinja2==dev
-
-.. _download page: http://pypi.python.org/pypi/Jinja2
-.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
-.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall
-.. _pip: http://pypi.python.org/pypi/pip
-.. _mercurial: http://www.selenic.com/mercurial/
-
-.. _enable-speedups:
-
-Enable the speedups Module
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-By default Jinja2 will not compile the speedups module. Enabling this
-will fail if you don't have the Python headers or a working compiler. This
-is often the case if you are installing Jinja2 from a windows machine.
-
-You can enable the speedups extension when installing using the
-``--with-speedups`` flag::
-
- sudo python setup.py --with-speedups install
-
-
-
-Basic API Usage
----------------
-
-This section gives you a brief introduction to the Python API for Jinja2
-templates.
-
-The most basic way to create a template and render it is through
-:class:`~jinja2.Template`. This however is not the recommended way to
-work with it if your templates are not loaded from strings but the file
-system or another data source:
-
->>> from jinja2 import Template
->>> template = Template('Hello {{ name }}!')
->>> template.render(name='John Doe')
-u'Hello John Doe!'
-
-By creating an instance of :class:`~jinja2.Template` you get back a new template
-object that provides a method called :meth:`~jinja2.Template.render` which when
-called with a dict or keyword arguments expands the template. The dict
-or keywords arguments passed to the template are the so-called "context"
-of the template.
-
-What you can see here is that Jinja2 is using unicode internally and the
-return value is an unicode string. So make sure that your application is
-indeed using unicode internally.
-
-
-Experimental Python 3 Support
------------------------------
-
-Jinja 2.3 brings experimental support for Python 3. It means that all
-unittests pass on the new version, but there might still be small bugs in
-there and behavior might be inconsistent. If you notice any bugs, please
-provide feedback in the `Jinja bug tracker`_.
-
-Also please keep in mind that the documentation is written with Python 2
-in mind, you will have to adapt the shown code examples to Python 3 syntax
-for yourself.
-
-
-.. _Jinja bug tracker: http://dev.pocoo.org/projects/jinja/
--- a/bundled/jinja2/docs/jinjaext.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- Jinja Documentation Extensions
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Support for automatically documenting filters and tests.
-
- :copyright: Copyright 2008 by Armin Ronacher.
- :license: BSD.
-"""
-import os
-import re
-import inspect
-import jinja2
-from itertools import islice
-from types import BuiltinFunctionType
-from docutils import nodes
-from docutils.statemachine import ViewList
-from sphinx.ext.autodoc import prepare_docstring
-from sphinx.application import TemplateBridge
-from pygments.style import Style
-from pygments.token import Keyword, Name, Comment, String, Error, \
- Number, Operator, Generic
-from jinja2 import Environment, FileSystemLoader
-
-
-def parse_rst(state, content_offset, doc):
- node = nodes.section()
- # hack around title style bookkeeping
- surrounding_title_styles = state.memo.title_styles
- surrounding_section_level = state.memo.section_level
- state.memo.title_styles = []
- state.memo.section_level = 0
- state.nested_parse(doc, content_offset, node, match_titles=1)
- state.memo.title_styles = surrounding_title_styles
- state.memo.section_level = surrounding_section_level
- return node.children
-
-
-class JinjaStyle(Style):
- title = 'Jinja Style'
- default_style = ""
- styles = {
- Comment: 'italic #aaaaaa',
- Comment.Preproc: 'noitalic #B11414',
- Comment.Special: 'italic #505050',
-
- Keyword: 'bold #B80000',
- Keyword.Type: '#808080',
-
- Operator.Word: 'bold #B80000',
-
- Name.Builtin: '#333333',
- Name.Function: '#333333',
- Name.Class: 'bold #333333',
- Name.Namespace: 'bold #333333',
- Name.Entity: 'bold #363636',
- Name.Attribute: '#686868',
- Name.Tag: 'bold #686868',
- Name.Decorator: '#686868',
-
- String: '#AA891C',
- Number: '#444444',
-
- Generic.Heading: 'bold #000080',
- Generic.Subheading: 'bold #800080',
- Generic.Deleted: '#aa0000',
- Generic.Inserted: '#00aa00',
- Generic.Error: '#aa0000',
- Generic.Emph: 'italic',
- Generic.Strong: 'bold',
- Generic.Prompt: '#555555',
- Generic.Output: '#888888',
- Generic.Traceback: '#aa0000',
-
- Error: '#F00 bg:#FAA'
- }
-
-
-_sig_re = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*(\(.*?\))')
-
-
-def format_function(name, aliases, func):
- lines = inspect.getdoc(func).splitlines()
- signature = '()'
- if isinstance(func, BuiltinFunctionType):
- match = _sig_re.match(lines[0])
- if match is not None:
- del lines[:1 + bool(lines and not lines[0])]
- signature = match.group(1)
- else:
- try:
- argspec = inspect.getargspec(func)
- if getattr(func, 'environmentfilter', False) or \
- getattr(func, 'contextfilter', False):
- del argspec[0][0]
- signature = inspect.formatargspec(*argspec)
- except:
- pass
- result = ['.. function:: %s%s' % (name, signature), '']
- result.extend(' ' + line for line in lines)
- if aliases:
- result.extend(('', ' :aliases: %s' % ', '.join(
- '``%s``' % x for x in sorted(aliases))))
- return result
-
-
-def dump_functions(mapping):
- def directive(dirname, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- reverse_mapping = {}
- for name, func in mapping.iteritems():
- reverse_mapping.setdefault(func, []).append(name)
- filters = []
- for func, names in reverse_mapping.iteritems():
- aliases = sorted(names, key=lambda x: len(x))
- name = aliases.pop()
- filters.append((name, aliases, func))
- filters.sort()
-
- result = ViewList()
- for name, aliases, func in filters:
- for item in format_function(name, aliases, func):
- result.append(item, '<jinjaext>')
-
- node = nodes.paragraph()
- state.nested_parse(result, content_offset, node)
- return node.children
- return directive
-
-
-from jinja2.defaults import DEFAULT_FILTERS, DEFAULT_TESTS
-jinja_filters = dump_functions(DEFAULT_FILTERS)
-jinja_tests = dump_functions(DEFAULT_TESTS)
-
-
-def jinja_nodes(dirname, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- from jinja2.nodes import Node
- doc = ViewList()
- def walk(node, indent):
- p = ' ' * indent
- sig = ', '.join(node.fields)
- doc.append(p + '.. autoclass:: %s(%s)' % (node.__name__, sig), '')
- if node.abstract:
- members = []
- for key, name in node.__dict__.iteritems():
- if not key.startswith('_') and \
- not hasattr(node.__base__, key) and callable(name):
- members.append(key)
- if members:
- members.sort()
- doc.append('%s :members: %s' % (p, ', '.join(members)), '')
- if node.__base__ != object:
- doc.append('', '')
- doc.append('%s :Node type: :class:`%s`' %
- (p, node.__base__.__name__), '')
- doc.append('', '')
- children = node.__subclasses__()
- children.sort(key=lambda x: x.__name__.lower())
- for child in children:
- walk(child, indent)
- walk(Node, 0)
- return parse_rst(state, content_offset, doc)
-
-
-def inject_toc(app, doctree, docname):
- titleiter = iter(doctree.traverse(nodes.title))
- try:
- # skip first title, we are not interested in that one
- titleiter.next()
- title = titleiter.next()
- # and check if there is at least another title
- titleiter.next()
- except StopIteration:
- return
- tocnode = nodes.section('')
- tocnode['classes'].append('toc')
- toctitle = nodes.section('')
- toctitle['classes'].append('toctitle')
- toctitle.append(nodes.title(text='Table Of Contents'))
- tocnode.append(toctitle)
- tocnode += doctree.document.settings.env.get_toc_for(docname)[0][1]
- title.parent.insert(title.parent.children.index(title), tocnode)
-
-
-def setup(app):
- app.add_directive('jinjafilters', jinja_filters, 0, (0, 0, 0))
- app.add_directive('jinjatests', jinja_tests, 0, (0, 0, 0))
- app.add_directive('jinjanodes', jinja_nodes, 0, (0, 0, 0))
- # uncomment for inline toc. links are broken unfortunately
- ##app.connect('doctree-resolved', inject_toc)
--- a/bundled/jinja2/docs/sandbox.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-Sandbox
-=======
-
-The Jinja2 sandbox can be used to evaluate untrusted code. Access to unsafe
-attributes and methods is prohibited.
-
-Assuming `env` is a :class:`SandboxedEnvironment` in the default configuration
-the following piece of code shows how it works:
-
->>> env.from_string("{{ func.func_code }}").render(func=lambda:None)
-u''
->>> env.from_string("{{ func.func_code.do_something }}").render(func=lambda:None)
-Traceback (most recent call last):
- ...
-SecurityError: access to attribute 'func_code' of 'function' object is unsafe.
-
-
-.. module:: jinja2.sandbox
-
-.. autoclass:: SandboxedEnvironment([options])
- :members: is_safe_attribute, is_safe_callable
-
-.. autoclass:: ImmutableSandboxedEnvironment([options])
-
-.. autoexception:: SecurityError
-
-.. autofunction:: unsafe
-
-.. autofunction:: is_internal_attribute
-
-.. autofunction:: modifies_known_mutable
-
-.. admonition:: Note
-
- The Jinja2 sandbox alone is no solution for perfect security. Especially
- for web applications you have to keep in mind that users may create
- templates with arbitrary HTML in so it's crucial to ensure that (if you
- are running multiple users on the same server) they can't harm each other
- via JavaScript insertions and much more.
-
- Also the sandbox is only as good as the configuration. We stronly
- recommend only passing non-shared resources to the template and use
- some sort of whitelisting for attributes.
-
- Also keep in mind that templates may raise runtime or compile time errors,
- so make sure to catch them.
--- a/bundled/jinja2/docs/switching.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-Switching from other Template Engines
-=====================================
-
-.. highlight:: html+jinja
-
-If you have used a different template engine in the past and want to swtich
-to Jinja2 here is a small guide that shows the basic syntatic and semantic
-changes between some common, similar text template engines for Python.
-
-Jinja1
-------
-
-Jinja2 is mostly compatible with Jinja1 in terms of API usage and template
-syntax. The differences between Jinja1 and 2 are explained in the following
-list.
-
-API
-~~~
-
-Loaders
- Jinja2 uses a different loader API. Because the internal representation
- of templates changed there is no longer support for external caching
- systems such as memcached. The memory consumed by templates is comparable
- with regular Python modules now and external caching doesn't give any
- advantage. If you have used a custom loader in the past have a look at
- the new :ref:`loader API <loaders>`.
-
-Loading templates from strings
- In the past it was possible to generate templates from a string with the
- default environment configuration by using `jinja.from_string`. Jinja2
- provides a :class:`Template` class that can be used to do the same, but
- with optional additional configuration.
-
-Automatic unicode conversion
- Jinja1 performed automatic conversion of bytestrings in a given encoding
- into unicode objects. This conversion is no longer implemented as it
- was inconsistent as most libraries are using the regular Python ASCII
- bytestring to Unicode conversion. An application powered by Jinja2
- *has to* use unicode internally everywhere or make sure that Jinja2 only
- gets unicode strings passed.
-
-i18n
- Jinja1 used custom translators for internationalization. i18n is now
- available as Jinja2 extension and uses a simpler, more gettext friendly
- interface and has support for babel. For more details see
- :ref:`i18n-extension`.
-
-Internal methods
- Jinja1 exposed a few internal methods on the environment object such
- as `call_function`, `get_attribute` and others. While they were marked
- as being an internal method it was possible to override them. Jinja2
- doesn't have equivalent methods.
-
-Sandbox
- Jinja1 was running sandbox mode by default. Few applications actually
- used that feature so it became optional in Jinja2. For more details
- about the sandboxed execution see :class:`SandboxedEnvironment`.
-
-Context
- Jinja1 had a stacked context as storage for variables passed to the
- environment. In Jinja2 a similar object exists but it doesn't allow
- modifications nor is it a singleton. As inheritance is dynamic now
- multiple context objects may exist during template evaluation.
-
-Filters and Tests
- Filters and tests are regular functions now. It's no longer necessary
- and allowed to use factory functions.
-
-
-Templates
-~~~~~~~~~
-
-Jinja2 has mostly the same syntax as Jinja1. What's different is that
-macros require parentheses around the argument list now.
-
-Additionally Jinja2 allows dynamic inheritance now and dynamic includes.
-The old helper function `rendertemplate` is gone now, `include` can be used
-instead. Includes no longer import macros and variable assignments, for
-that the new `import` tag is used. This concept is explained in the
-:ref:`import` documentation.
-
-Another small change happened in the `for`-tag. The special loop variable
-doesn't have a `parent` attribute, instead you have to alias the loop
-yourself. See :ref:`accessing-the-parent-loop` for more details.
-
-
-Django
-------
-
-If you have previously worked with Django templates, you should find
-Jinja2 very familiar. In fact, most of the syntax elements look and
-work the same.
-
-However, Jinja2 provides some more syntax elements covered in the
-documentation and some work a bit different.
-
-This section covers the template changes. As the API is fundamentally
-different we won't cover it here.
-
-Method Calls
-~~~~~~~~~~~~
-
-In Django method calls work implicitly. With Jinja2 you have to specify that
-you want to call an object. Thus this Django code::
-
- {% for page in user.get_created_pages %}
- ...
- {% endfor %}
-
-will look like this in Jinja::
-
- {% for page in user.get_created_pages() %}
- ...
- {% endfor %}
-
-This allows you to pass variables to the function which is also used for macros
-which is not possible in Django.
-
-Conditions
-~~~~~~~~~~
-
-In Django you can use the following constructs to check for equality::
-
- {% ifequal foo "bar" %}
- ...
- {% else %}
- ...
- {% endifequal %}
-
-In Jinja2 you can use the normal if statement in combination with operators::
-
- {% if foo == 'bar' %}
- ...
- {% else %}
- ...
- {% endif %}
-
-You can also have multiple elif branches in your template::
-
- {% if something %}
- ...
- {% elif otherthing %}
- ...
- {% elif foothing %}
- ...
- {% else %}
- ...
- {% endif %}
-
-Filter Arguments
-~~~~~~~~~~~~~~~~
-
-Jinja2 provides more than one argument for filters. Also the syntax for
-argument passing is different. A template that looks like this in Django::
-
- {{ items|join:", " }}
-
-looks like this in Jinja2::
-
- {{ items|join(', ') }}
-
-In fact it's a bit more verbose but it allows different types of arguments -
-including variables - and more than one of them.
-
-Tests
-~~~~~
-
-In addition to filters there also are tests you can perform using the is
-operator. Here are some examples::
-
- {% if user.user_id is odd %}
- {{ user.username|e }} is odd
- {% else %}
- hmm. {{ user.username|e }} looks pretty normal
- {% endif %}
-
-Loops
-~~~~~
-
-For loops work very similar to Django, the only incompatibility is that in
-Jinja2 the special variable for the loop context is called `loop` and not
-`forloop` like in Django.
-
-Cycle
-~~~~~
-
-The ``{% cycle %}`` tag does not exist in Jinja because of it's implicit
-nature. However you can achieve mostly the same by using the `cycle`
-method on a loop object.
-
-The following Django template::
-
- {% for user in users %}
- <li class="{% cycle 'odd' 'even' %}">{{ user }}</li>
- {% endfor %}
-
-Would look like this in Jinja::
-
- {% for user in users %}
- <li class="{{ loop.cycle('odd', 'even') }}">{{ user }}</li>
- {% endfor %}
-
-There is no equivalent of ``{% cycle ... as variable %}``.
-
-
-Mako
-----
-
-.. highlight:: html+mako
-
-If you have used Mako so far and want to switch to Jinja2 you can configure
-Jinja2 to look more like Mako:
-
-.. sourcecode:: python
-
- env = Environment('<%', '%>', '${', '}', '%')
-
-Once the environment is configure like that Jinja2 should be able to interpret
-a small subset of Mako templates. Jinja2 does not support embedded Python code
-so you would have to move that out of the template. The syntax for defs (in
-Jinja2 defs are called macros) and template inheritance is different too. The
-following Mako template::
-
- <%inherit file="layout.html" />
- <%def name="title()">Page Title</%def>
- <ul>
- % for item in list:
- <li>${item}</li>
- % endfor
- </ul>
-
-Looks like this in Jinja2 with the above configuration::
-
- <% extends "layout.html" %>
- <% block title %>Page Title<% endblock %>
- <% block body %>
- <ul>
- % for item in list:
- <li>${item}</li>
- % endfor
- </ul>
- <% endblock %>
--- a/bundled/jinja2/docs/templates.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1310 +0,0 @@
-Template Designer Documentation
-===============================
-
-.. highlight:: html+jinja
-
-This document describes the syntax and semantics of the template engine and
-will be most useful as reference to those creating Jinja templates. As the
-template engine is very flexible the configuration from the application might
-be slightly different from here in terms of delimiters and behavior of
-undefined values.
-
-
-Synopsis
---------
-
-A template is simply a text file. It can generate any text-based format
-(HTML, XML, CSV, LaTeX, etc.). It doesn't have a specific extension,
-``.html`` or ``.xml`` are just fine.
-
-A template contains **variables** or **expressions**, which get replaced with
-values when the template is evaluated, and tags, which control the logic of
-the template. The template syntax is heavily inspired by Django and Python.
-
-Below is a minimal template that illustrates a few basics. We will cover
-the details later in that document::
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
- <html lang="en">
- <head>
- <title>My Webpage</title>
- </head>
- <body>
- <ul id="navigation">
- {% for item in navigation %}
- <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
- {% endfor %}
- </ul>
-
- <h1>My Webpage</h1>
- {{ a_variable }}
- </body>
- </html>
-
-This covers the default settings. The application developer might have
-changed the syntax from ``{% foo %}`` to ``<% foo %>`` or something similar.
-
-There are two kinds of delimiers. ``{% ... %}`` and ``{{ ... }}``. The first
-one is used to execute statements such as for-loops or assign values, the
-latter prints the result of the expression to the template.
-
-.. _variables:
-
-Variables
----------
-
-The application passes variables to the templates you can mess around in the
-template. Variables may have attributes or elements on them you can access
-too. How a variable looks like, heavily depends on the application providing
-those.
-
-You can use a dot (``.``) to access attributes of a variable, alternative the
-so-called "subscript" syntax (``[]``) can be used. The following lines do
-the same::
-
- {{ foo.bar }}
- {{ foo['bar'] }}
-
-It's important to know that the curly braces are *not* part of the variable
-but the print statement. If you access variables inside tags don't put the
-braces around.
-
-If a variable or attribute does not exist you will get back an undefined
-value. What you can do with that kind of value depends on the application
-configuration, the default behavior is that it evaluates to an empty string
-if printed and that you can iterate over it, but every other operation fails.
-
-.. _notes-on-subscriptions:
-
-.. admonition:: Implementation
-
- For convenience sake ``foo.bar`` in Jinja2 does the following things on
- the Python layer:
-
- - check if there is an attribute called `bar` on `foo`.
- - if there is not, check if there is an item ``'bar'`` in `foo`.
- - if there is not, return an undefined object.
-
- ``foo['bar']`` on the other hand works mostly the same with the a small
- difference in the order:
-
- - check if there is an item ``'bar'`` in `foo`.
- - if there is not, check if there is an attribute called `bar` on `foo`.
- - if there is not, return an undefined object.
-
- This is important if an object has an item or attribute with the same
- name. Additionally there is the :func:`attr` filter that just looks up
- attributes.
-
-.. _filters:
-
-Filters
--------
-
-Variables can by modified by **filters**. Filters are separated from the
-variable by a pipe symbol (``|``) and may have optional arguments in
-parentheses. Multiple filters can be chained. The output of one filter is
-applied to the next.
-
-``{{ name|striptags|title }}`` for example will remove all HTML Tags from the
-`name` and title-cases it. Filters that accept arguments have parentheses
-around the arguments, like a function call. This example will join a list
-by commas: ``{{ list|join(', ') }}``.
-
-The :ref:`builtin-filters` below describes all the builtin filters.
-
-.. _tests:
-
-Tests
------
-
-Beside filters there are also so called "tests" available. Tests can be used
-to test a variable against a common expression. To test a variable or
-expression you add `is` plus the name of the test after the variable. For
-example to find out if a variable is defined you can do ``name is defined``
-which will then return true or false depending on if `name` is defined.
-
-Tests can accept arguments too. If the test only takes one argument you can
-leave out the parentheses to group them. For example the following two
-expressions do the same::
-
- {% if loop.index is divisibleby 3 %}
- {% if loop.index is divisibleby(3) %}
-
-The :ref:`builtin-tests` below describes all the builtin tests.
-
-
-Comments
---------
-
-To comment-out part of a line in a template, use the comment syntax which is
-by default set to ``{# ... #}``. This is useful to comment out parts of the
-template for debugging or to add information for other template designers or
-yourself::
-
- {# note: disabled template because we no longer use this
- {% for user in users %}
- ...
- {% endfor %}
- #}
-
-
-Whitespace Control
-------------------
-
-In the default configuration whitespace is not further modified by the
-template engine, so each whitespace (spaces, tabs, newlines etc.) is returned
-unchanged. If the application configures Jinja to `trim_blocks` the first
-newline after a a template tag is removed automatically (like in PHP).
-
-But you can also strip whitespace in templates by hand. If you put an minus
-sign (``-``) to the start or end of an block (for example a for tag), a
-comment or variable expression you can remove the whitespaces after or before
-that block::
-
- {% for item in seq -%}
- {{ item }}
- {%- endfor %}
-
-This will yield all elements without whitespace between them. If `seq` was
-a list of numbers from ``1`` to ``9`` the output would be ``123456789``.
-
-If :ref:`line-statements` are enabled they strip leading whitespace
-automatically up to the beginning of the line.
-
-.. admonition:: Note
-
- You must not use a whitespace between the tag and the minus sign.
-
- **valid**::
-
- {%- if foo -%}...{% endif %}
-
- **invalid**::
-
- {% - if foo - %}...{% endif %}
-
-
-Escaping
---------
-
-It is sometimes desirable or even necessary to have Jinja ignore parts it
-would otherwise handle as variables or blocks. For example if the default
-syntax is used and you want to use ``{{`` as raw string in the template and
-not start a variable you have to use a trick.
-
-The easiest way is to output the variable delimiter (``{{``) by using a
-variable expression::
-
- {{ '{{' }}
-
-For bigger sections it makes sense to mark a block `raw`. For example to
-put Jinja syntax as example into a template you can use this snippet::
-
- {% raw %}
- <ul>
- {% for item in seq %}
- <li>{{ item }}</li>
- {% endfor %}
- </ul>
- {% endraw %}
-
-
-.. _line-statements:
-
-Line Statements
----------------
-
-If line statements are enabled by the application it's possible to mark a
-line as a statement. For example if the line statement prefix is configured
-to ``#`` the following two examples are equivalent::
-
- <ul>
- # for item in seq
- <li>{{ item }}</li>
- # endfor
- </ul>
-
- <ul>
- {% for item in seq %}
- <li>{{ item }}</li>
- {% endfor %}
- </ul>
-
-The line statement prefix can appear anywhere on the line as long as no text
-precedes it. For better readability statements that start a block (such as
-`for`, `if`, `elif` etc.) may end with a colon::
-
- # for item in seq:
- ...
- # endfor
-
-
-.. admonition:: Note
-
- Line statements can span multiple lines if there are open parentheses,
- braces or brackets::
-
- <ul>
- # for href, caption in [('index.html', 'Index'),
- ('about.html', 'About')]:
- <li><a href="{{ href }}">{{ caption }}</a></li>
- # endfor
- </ul>
-
-Since Jinja 2.2 line-based comments are available as well. For example if
-the line-comment prefix is configured to be ``##`` everything from ``##`` to
-the end of the line is ignored (excluding the newline sign)::
-
- # for item in seq:
- <li>{{ item }}</li> ## this comment is ignored
- # endfor
-
-
-.. _template-inheritance:
-
-Template Inheritance
---------------------
-
-The most powerful part of Jinja is template inheritance. Template inheritance
-allows you to build a base "skeleton" template that contains all the common
-elements of your site and defines **blocks** that child templates can override.
-
-Sounds complicated but is very basic. It's easiest to understand it by starting
-with an example.
-
-
-Base Template
-~~~~~~~~~~~~~
-
-This template, which we'll call ``base.html``, defines a simple HTML skeleton
-document that you might use for a simple two-column page. It's the job of
-"child" templates to fill the empty blocks with content::
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
- <html lang="en">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- {% block head %}
- <link rel="stylesheet" href="style.css" />
- <title>{% block title %}{% endblock %} - My Webpage</title>
- {% endblock %}
- </head>
- <body>
- <div id="content">{% block content %}{% endblock %}</div>
- <div id="footer">
- {% block footer %}
- © Copyright 2008 by <a href="http://domain.invalid/">you</a>.
- {% endblock %}
- </div>
- </body>
-
-In this example, the ``{% block %}`` tags define four blocks that child templates
-can fill in. All the `block` tag does is to tell the template engine that a
-child template may override those portions of the template.
-
-Child Template
-~~~~~~~~~~~~~~
-
-A child template might look like this::
-
- {% extends "base.html" %}
- {% block title %}Index{% endblock %}
- {% block head %}
- {{ super() }}
- <style type="text/css">
- .important { color: #336699; }
- </style>
- {% endblock %}
- {% block content %}
- <h1>Index</h1>
- <p class="important">
- Welcome on my awesome homepage.
- </p>
- {% endblock %}
-
-The ``{% extends %}`` tag is the key here. It tells the template engine that
-this template "extends" another template. When the template system evaluates
-this template, first it locates the parent. The extends tag should be the
-first tag in the template. Everything before it is printed out normally and
-may cause confusion. For details about this behavior and how to take
-advantage of it, see :ref:`null-master-fallback`.
-
-The filename of the template depends on the template loader. For example the
-:class:`FileSystemLoader` allows you to access other templates by giving the
-filename. You can access templates in subdirectories with an slash::
-
- {% extends "layout/default.html" %}
-
-But this behavior can depend on the application embedding Jinja. Note that
-since the child template doesn't define the ``footer`` block, the value from
-the parent template is used instead.
-
-You can't define multiple ``{% block %}`` tags with the same name in the
-same template. This limitation exists because a block tag works in "both"
-directions. That is, a block tag doesn't just provide a hole to fill - it
-also defines the content that fills the hole in the *parent*. If there
-were two similarly-named ``{% block %}`` tags in a template, that template's
-parent wouldn't know which one of the blocks' content to use.
-
-If you want to print a block multiple times you can however use the special
-`self` variable and call the block with that name::
-
- <title>{% block title %}{% endblock %}</title>
- <h1>{{ self.title() }}</h1>
- {% block body %}{% endblock %}
-
-
-Super Blocks
-~~~~~~~~~~~~
-
-It's possible to render the contents of the parent block by calling `super`.
-This gives back the results of the parent block::
-
- {% block sidebar %}
- <h3>Table Of Contents</h3>
- ...
- {{ super() }}
- {% endblock %}
-
-
-Named Block End-Tags
-~~~~~~~~~~~~~~~~~~~~
-
-Jinja2 allows you to put the name of the block after the end tag for better
-readability::
-
- {% block sidebar %}
- {% block inner_sidebar %}
- ...
- {% endblock inner_sidebar %}
- {% endblock sidebar %}
-
-However the name after the `endblock` word must match the block name.
-
-
-Block Nesting and Scope
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Blocks can be nested for more complex layouts. However per default blocks
-may not access variables from outer scopes::
-
- {% for item in seq %}
- <li>{% block loop_item %}{{ item }}{% endblock %}</li>
- {% endfor %}
-
-This example would output empty ``<li>`` items because `item` is unavailable
-inside the block. The reason for this is that if the block is replaced by
-a child template a variable would appear that was not defined in the block or
-passed to the context.
-
-Starting with Jinja 2.2 you can explicitly specify that variables are
-available in a block by setting the block to "scoped" by adding the `scoped`
-modifier to a block declaration::
-
- {% for item in seq %}
- <li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
- {% endfor %}
-
-When overriding a block the `scoped` modifier does not have to be provided.
-
-
-Template Objects
-~~~~~~~~~~~~~~~~
-
-.. versionchanged:: 2.4
-
-If a template object was passed to the template context you can
-extend from that object as well. Assuming the calling code passes
-a layout template as `layout_template` to the environment, this
-code works::
-
- {% extends layout_template %}
-
-Previously the `layout_template` variable had to be a string with
-the layout template's filename for this to work.
-
-
-HTML Escaping
--------------
-
-When generating HTML from templates, there's always a risk that a variable will
-include characters that affect the resulting HTML. There are two approaches:
-manually escaping each variable or automatically escaping everything by default.
-
-Jinja supports both, but what is used depends on the application configuration.
-The default configuaration is no automatic escaping for various reasons:
-
-- escaping everything except of safe values will also mean that Jinja is
- escaping variables known to not include HTML such as numbers which is
- a huge performance hit.
-
-- The information about the safety of a variable is very fragile. It could
- happen that by coercing safe and unsafe values the return value is double
- escaped HTML.
-
-Working with Manual Escaping
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If manual escaping is enabled it's **your** responsibility to escape
-variables if needed. What to escape? If you have a variable that *may*
-include any of the following chars (``>``, ``<``, ``&``, or ``"``) you
-**have to** escape it unless the variable contains well-formed and trusted
-HTML. Escaping works by piping the variable through the ``|e`` filter:
-``{{ user.username|e }}``.
-
-Working with Automatic Escaping
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When automatic escaping is enabled everything is escaped by default except
-for values explicitly marked as safe. Those can either be marked by the
-application or in the template by using the `|safe` filter. The main
-problem with this approach is that Python itself doesn't have the concept
-of tainted values so the information if a value is safe or unsafe can get
-lost. If the information is lost escaping will take place which means that
-you could end up with double escaped contents.
-
-Double escaping is easy to avoid however, just rely on the tools Jinja2
-provides and don't use builtin Python constructs such as the string modulo
-operator.
-
-Functions returning template data (macros, `super`, `self.BLOCKNAME`) return
-safe markup always.
-
-String literals in templates with automatic escaping are considered unsafe
-too. The reason for this is that the safe string is an extension to Python
-and not every library will work properly with it.
-
-
-List of Control Structures
---------------------------
-
-A control structure refers to all those things that control the flow of a
-program - conditionals (i.e. if/elif/else), for-loops, as well as things like
-macros and blocks. Control structures appear inside ``{% ... %}`` blocks
-in the default syntax.
-
-For
-~~~
-
-Loop over each item in a sequence. For example, to display a list of users
-provided in a variable called `users`::
-
- <h1>Members</h1>
- <ul>
- {% for user in users %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
- </ul>
-
-Inside of a for loop block you can access some special variables:
-
-+-----------------------+---------------------------------------------------+
-| Variable | Description |
-+=======================+===================================================+
-| `loop.index` | The current iteration of the loop. (1 indexed) |
-+-----------------------+---------------------------------------------------+
-| `loop.index0` | The current iteration of the loop. (0 indexed) |
-+-----------------------+---------------------------------------------------+
-| `loop.revindex` | The number of iterations from the end of the loop |
-| | (1 indexed) |
-+-----------------------+---------------------------------------------------+
-| `loop.revindex0` | The number of iterations from the end of the loop |
-| | (0 indexed) |
-+-----------------------+---------------------------------------------------+
-| `loop.first` | True if first iteration. |
-+-----------------------+---------------------------------------------------+
-| `loop.last` | True if last iteration. |
-+-----------------------+---------------------------------------------------+
-| `loop.length` | The number of items in the sequence. |
-+-----------------------+---------------------------------------------------+
-| `loop.cycle` | A helper function to cycle between a list of |
-| | sequences. See the explanation below. |
-+-----------------------+---------------------------------------------------+
-
-Within a for-loop, it's possible to cycle among a list of strings/variables
-each time through the loop by using the special `loop.cycle` helper::
-
- {% for row in rows %}
- <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
- {% endfor %}
-
-With Jinja 2.1 an extra `cycle` helper exists that allows loop-unbound
-cycling. For more information have a look at the :ref:`builtin-globals`.
-
-.. _loop-filtering:
-
-Unlike in Python it's not possible to `break` or `continue` in a loop. You
-can however filter the sequence during iteration which allows you to skip
-items. The following example skips all the users which are hidden::
-
- {% for user in users if not user.hidden %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
-
-The advantage is that the special `loop` variable will count correctly thus
-not counting the users not iterated over.
-
-If no iteration took place because the sequence was empty or the filtering
-removed all the items from the sequence you can render a replacement block
-by using `else`::
-
- <ul>
- {% for user in users %}
- <li>{{ user.username|e }}</li>
- {% else %}
- <li><em>no users found</em></li>
- {% endfor %}
- </ul>
-
-It is also possible to use loops recursively. This is useful if you are
-dealing with recursive data such as sitemaps. To use loops recursively you
-basically have to add the `recursive` modifier to the loop definition and
-call the `loop` variable with the new iterable where you want to recurse.
-
-The following example implements a sitemap with recursive loops::
-
- <ul class="sitemap">
- {%- for item in sitemap recursive %}
- <li><a href="{{ item.href|e }}">{{ item.title }}</a>
- {%- if item.children -%}
- <ul class="submenu">{{ loop(item.children) }}</ul>
- {%- endif %}</li>
- {%- endfor %}
- </ul>
-
-
-If
-~~
-
-The `if` statement in Jinja is comparable with the if statements of Python.
-In the simplest form you can use it to test if a variable is defined, not
-empty or not false::
-
- {% if users %}
- <ul>
- {% for user in users %}
- <li>{{ user.username|e }}</li>
- {% endfor %}
- </ul>
- {% endif %}
-
-For multiple branches `elif` and `else` can be used like in Python. You can
-use more complex :ref:`expressions` there too::
-
- {% if kenny.sick %}
- Kenny is sick.
- {% elif kenny.dead %}
- You killed Kenny! You bastard!!!
- {% else %}
- Kenny looks okay --- so far
- {% endif %}
-
-If can also be used as :ref:`inline expression <if-expression>` and for
-:ref:`loop filtering <loop-filtering>`.
-
-
-Macros
-~~~~~~
-
-Macros are comparable with functions in regular programming languages. They
-are useful to put often used idioms into reusable functions to not repeat
-yourself.
-
-Here a small example of a macro that renders a form element::
-
- {% macro input(name, value='', type='text', size=20) -%}
- <input type="{{ type }}" name="{{ name }}" value="{{
- value|e }}" size="{{ size }}">
- {%- endmacro %}
-
-The macro can then be called like a function in the namespace::
-
- <p>{{ input('username') }}</p>
- <p>{{ input('password', type='password') }}</p>
-
-If the macro was defined in a different template you have to
-:ref:`import <import>` it first.
-
-Inside macros you have access to three special variables:
-
-`varargs`
- If more positional arguments are passed to the macro than accepted by the
- macro they end up in the special `varargs` variable as list of values.
-
-`kwargs`
- Like `varargs` but for keyword arguments. All unconsumed keyword
- arguments are stored in this special variable.
-
-`caller`
- If the macro was called from a :ref:`call<call>` tag the caller is stored
- in this variable as macro which can be called.
-
-Macros also expose some of their internal details. The following attributes
-are available on a macro object:
-
-`name`
- The name of the macro. ``{{ input.name }}`` will print ``input``.
-
-`arguments`
- A tuple of the names of arguments the macro accepts.
-
-`defaults`
- A tuple of default values.
-
-`catch_kwargs`
- This is `true` if the macro accepts extra keyword arguments (ie: accesses
- the special `kwargs` variable).
-
-`catch_varargs`
- This is `true` if the macro accepts extra positional arguments (ie:
- accesses the special `varargs` variable).
-
-`caller`
- This is `true` if the macro accesses the special `caller` variable and may
- be called from a :ref:`call<call>` tag.
-
-If a macro name starts with an underscore it's not exported and can't
-be imported.
-
-
-.. _call:
-
-Call
-~~~~
-
-In some cases it can be useful to pass a macro to another macro. For this
-purpose you can use the special `call` block. The following example shows
-a macro that takes advantage of the call functionality and how it can be
-used::
-
- {% macro render_dialog(title, class='dialog') -%}
- <div class="{{ class }}">
- <h2>{{ title }}</h2>
- <div class="contents">
- {{ caller() }}
- </div>
- </div>
- {%- endmacro %}
-
- {% call render_dialog('Hello World') %}
- This is a simple dialog rendered by using a macro and
- a call block.
- {% endcall %}
-
-It's also possible to pass arguments back to the call block. This makes it
-useful as replacement for loops. Generally speaking a call block works
-exactly like an macro, just that it doesn't have a name.
-
-Here an example of how a call block can be used with arguments::
-
- {% macro dump_users(users) -%}
- <ul>
- {%- for user in users %}
- <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
- {%- endfor %}
- </ul>
- {%- endmacro %}
-
- {% call(user) dump_users(list_of_user) %}
- <dl>
- <dl>Realname</dl>
- <dd>{{ user.realname|e }}</dd>
- <dl>Description</dl>
- <dd>{{ user.description }}</dd>
- </dl>
- {% endcall %}
-
-
-Filters
-~~~~~~~
-
-Filter sections allow you to apply regular Jinja2 filters on a block of
-template data. Just wrap the code in the special `filter` section::
-
- {% filter upper %}
- This text becomes uppercase
- {% endfilter %}
-
-
-Assignments
-~~~~~~~~~~~
-
-Inside code blocks you can also assign values to variables. Assignments at
-top level (outside of blocks, macros or loops) are exported from the template
-like top level macros and can be imported by other templates.
-
-Assignments use the `set` tag and can have multiple targets::
-
- {% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
- {% set key, value = call_something() %}
-
-
-Extends
-~~~~~~~
-
-The `extends` tag can be used to extend a template from another one. You
-can have multiple of them in a file but only one of them may be executed
-at the time. See the section about :ref:`template-inheritance` above.
-
-
-Block
-~~~~~
-
-Blocks are used for inheritance and act as placeholders and replacements
-at the same time. They are documented in detail as part of the section
-about :ref:`template-inheritance`.
-
-
-Include
-~~~~~~~
-
-The `include` statement is useful to include a template and return the
-rendered contents of that file into the current namespace::
-
- {% include 'header.html' %}
- Body
- {% include 'footer.html' %}
-
-Included templates have access to the variables of the active context by
-default. For more details about context behavior of imports and includes
-see :ref:`import-visibility`.
-
-From Jinja 2.2 onwards you can mark an include with ``ignore missing`` in
-which case Jinja will ignore the statement if the template to be ignored
-does not exist. When combined with ``with`` or ``without context`` it has
-to be placed *before* the context visibility statement. Here some valid
-examples::
-
- {% include "sidebar.html" ignore missing %}
- {% include "sidebar.html" ignore missing with context %}
- {% include "sidebar.html" ignore missing without context %}
-
-.. versionadded:: 2.2
-
-You can also provide a list of templates that are checked for existence
-before inclusion. The first template that exists will be included. If
-`ignore missing` is given, it will fall back to rendering nothing if
-none of the templates exist, otherwise it will raise an exception.
-
-Example::
-
- {% include ['page_detailed.html', 'page.html'] %}
- {% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}
-
-.. versionchanged:: 2.4
- If a template object was passed to the template context you can
- include that object using `include`.
-
-.. _import:
-
-Import
-~~~~~~
-
-Jinja2 supports putting often used code into macros. These macros can go into
-different templates and get imported from there. This works similar to the
-import statements in Python. It's important to know that imports are cached
-and imported templates don't have access to the current template variables,
-just the globals by defualt. For more details about context behavior of
-imports and includes see :ref:`import-visibility`.
-
-There are two ways to import templates. You can import the complete template
-into a variable or request specific macros / exported variables from it.
-
-Imagine we have a helper module that renders forms (called `forms.html`)::
-
- {% macro input(name, value='', type='text') -%}
- <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
- {%- endmacro %}
-
- {%- macro textarea(name, value='', rows=10, cols=40) -%}
- <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols
- }}">{{ value|e }}</textarea>
- {%- endmacro %}
-
-The easiest and most flexible is importing the whole module into a variable.
-That way you can access the attributes::
-
- {% import 'forms.html' as forms %}
- <dl>
- <dt>Username</dt>
- <dd>{{ forms.input('username') }}</dd>
- <dt>Password</dt>
- <dd>{{ forms.input('password', type='password') }}</dd>
- </dl>
- <p>{{ forms.textarea('comment') }}</p>
-
-
-Alternatively you can import names from the template into the current
-namespace::
-
- {% from 'forms.html' import input as input_field, textarea %}
- <dl>
- <dt>Username</dt>
- <dd>{{ input_field('username') }}</dd>
- <dt>Password</dt>
- <dd>{{ input_field('password', type='password') }}</dd>
- </dl>
- <p>{{ textarea('comment') }}</p>
-
-Macros and variables starting with one ore more underscores are private and
-cannot be imported.
-
-.. versionchanged:: 2.4
- If a template object was passed to the template context you can
- import from that object.
-
-
-.. _import-visibility:
-
-Import Context Behavior
------------------------
-
-Per default included templates are passed the current context and imported
-templates not. The reason for this is that imports unlike includes are
-cached as imports are often used just as a module that holds macros.
-
-This however can be changed of course explicitly. By adding `with context`
-or `without context` to the import/include directive the current context
-can be passed to the template and caching is disabled automatically.
-
-Here two examples::
-
- {% from 'forms.html' import input with context %}
- {% include 'header.html' without context %}
-
-.. admonition:: Note
-
- In Jinja 2.0 the context that was passed to the included template
- did not include variables defined in the template. As a matter of
- fact this did not work::
-
- {% for box in boxes %}
- {% include "render_box.html" %}
- {% endfor %}
-
- The included template ``render_box.html`` is not able to access
- `box` in Jinja 2.0, but in Jinja 2.1.
-
-
-.. _expressions:
-
-Expressions
------------
-
-Jinja allows basic expressions everywhere. These work very similar to regular
-Python and even if you're not working with Python you should feel comfortable
-with it.
-
-Literals
-~~~~~~~~
-
-The simplest form of expressions are literals. Literals are representations
-for Python objects such as strings and numbers. The following literals exist:
-
-"Hello World":
- Everything between two double or single quotes is a string. They are
- useful whenever you need a string in the template (for example as
- arguments to function calls, filters or just to extend or include a
- template).
-
-42 / 42.23:
- Integers and floating point numbers are created by just writing the
- number down. If a dot is present the number is a float, otherwise an
- integer. Keep in mind that for Python ``42`` and ``42.0`` is something
- different.
-
-['list', 'of', 'objects']:
- Everything between two brackets is a list. Lists are useful to store
- sequential data in or to iterate over them. For example you can easily
- create a list of links using lists and tuples with a for loop::
-
- <ul>
- {% for href, caption in [('index.html', 'Index'), ('about.html', 'About'),
- ('downloads.html', 'Downloads')] %}
- <li><a href="{{ href }}">{{ caption }}</a></li>
- {% endfor %}
- </ul>
-
-('tuple', 'of', 'values'):
- Tuples are like lists, just that you can't modify them. If the tuple
- only has one item you have to end it with a comma. Tuples are usually
- used to represent items of two or more elements. See the example above
- for more details.
-
-{'dict': 'of', 'key': 'and', 'value': 'pairs'}:
- A dict in Python is a structure that combines keys and values. Keys must
- be unique and always have exactly one value. Dicts are rarely used in
- templates, they are useful in some rare cases such as the :func:`xmlattr`
- filter.
-
-true / false:
- true is always true and false is always false.
-
-.. admonition:: Note
-
- The special constants `true`, `false` and `none` are indeed lowercase.
- Because that caused confusion in the past, when writing `True` expands
- to an undefined variable that is considered false, all three of them can
- be written in title case too (`True`, `False`, and `None`). However for
- consistency (all Jinja identifiers are lowercase) you should use the
- lowercase versions.
-
-Math
-~~~~
-
-Jinja allows you to calculate with values. This is rarely useful in templates
-but exists for completeness' sake. The following operators are supported:
-
-\+
- Adds two objects together. Usually the objects are numbers but if both are
- strings or lists you can concatenate them this way. This however is not
- the preferred way to concatenate strings! For string concatenation have
- a look at the ``~`` operator. ``{{ 1 + 1 }}`` is ``2``.
-
-\-
- Substract the second number from the first one. ``{{ 3 - 2 }}`` is ``1``.
-
-/
- Divide two numbers. The return value will be a floating point number.
- ``{{ 1 / 2 }}`` is ``{{ 0.5 }}``.
-
-//
- Divide two numbers and return the truncated integer result.
- ``{{ 20 / 7 }}`` is ``2``.
-
-%
- Calculate the remainder of an integer division. ``{{ 11 % 7 }}`` is ``4``.
-
-\*
- Multiply the left operand with the right one. ``{{ 2 * 2 }}`` would
- return ``4``. This can also be used to repeat a string multiple times.
- ``{{ '=' * 80 }}`` would print a bar of 80 equal signs.
-
-\**
- Raise the left operand to the power of the right operand. ``{{ 2**3 }}``
- would return ``8``.
-
-Logic
-~~~~~
-
-For `if` statements, `for` filtering or `if` expressions it can be useful to
-combine multiple expressions:
-
-and
- Return true if the left and the right operand is true.
-
-or
- Return true if the left or the right operand is true.
-
-not
- negate a statement (see below).
-
-(expr)
- group an expression.
-
-.. admonition:: Note
-
- The ``is`` and ``in`` operators support negation using an infix notation
- too: ``foo is not bar`` and ``foo not in bar`` instead of ``not foo is bar``
- and ``not foo in bar``. All other expressions require a prefix notation:
- ``not (foo and bar).``
-
-
-Other Operators
-~~~~~~~~~~~~~~~
-
-The following operators are very useful but don't fit into any of the other
-two categories:
-
-in
- Perform sequence / mapping containment test. Returns true if the left
- operand is contained in the right. ``{{ 1 in [1, 2, 3] }}`` would for
- example return true.
-
-is
- Performs a :ref:`test <tests>`.
-
-\|
- Applies a :ref:`filter <filters>`.
-
-~
- Converts all operands into strings and concatenates them.
- ``{{ "Hello " ~ name ~ "!" }}`` would return (assuming `name` is
- ``'John'``) ``Hello John!``.
-
-()
- Call a callable: ``{{ post.render() }}``. Inside of the parentheses you
- can use positional arguments and keyword arguments like in python:
- ``{{ post.render(user, full=true) }}``.
-
-. / []
- Get an attribute of an object. (See :ref:`variables`)
-
-
-.. _if-expression:
-
-If Expression
-~~~~~~~~~~~~~
-
-It is also possible to use inline `if` expressions. These are useful in some
-situations. For example you can use this to extend from one template if a
-variable is defined, otherwise from the default layout template::
-
- {% extends layout_template if layout_template is defined else 'master.html' %}
-
-The general syntax is ``<do something> if <something is true> else <do
-something else>``.
-
-The `else` part is optional. If not provided the else block implicitly
-evaluates into an undefined object::
-
- {{ '[%s]' % page.title if page.title }}
-
-
-.. _builtin-filters:
-
-List of Builtin Filters
------------------------
-
-.. jinjafilters::
-
-
-.. _builtin-tests:
-
-List of Builtin Tests
----------------------
-
-.. jinjatests::
-
-.. _builtin-globals:
-
-List of Global Functions
-------------------------
-
-The following functions are available in the global scope by default:
-
-.. function:: range([start,] stop[, step])
-
- Return a list containing an arithmetic progression of integers.
- range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
- When step is given, it specifies the increment (or decrement).
- For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
- These are exactly the valid indices for a list of 4 elements.
-
- This is useful to repeat a template block multiple times for example
- to fill a list. Imagine you have 7 users in the list but you want to
- render three empty items to enforce a height with CSS::
-
- <ul>
- {% for user in users %}
- <li>{{ user.username }}</li>
- {% endfor %}
- {% for number in range(10 - users|count) %}
- <li class="empty"><span>...</span></li>
- {% endfor %}
- </ul>
-
-.. function:: lipsum(n=5, html=True, min=20, max=100)
-
- Generates some lorem ipsum for the template. Per default five paragraphs
- with HTML are generated each paragraph between 20 and 100 words. If html
- is disabled regular text is returned. This is useful to generate simple
- contents for layout testing.
-
-.. function:: dict(\**items)
-
- A convenient alternative to dict literals. ``{'foo': 'bar'}`` is the same
- as ``dict(foo='bar')``.
-
-.. class:: cycler(\*items)
-
- The cycler allows you to cycle among values similar to how `loop.cycle`
- works. Unlike `loop.cycle` however you can use this cycler outside of
- loops or over multiple loops.
-
- This is for example very useful if you want to show a list of folders and
- files, with the folders on top, but both in the same list with alternating
- row colors.
-
- The following example shows how `cycler` can be used::
-
- {% set row_class = cycler('odd', 'even') %}
- <ul class="browser">
- {% for folder in folders %}
- <li class="folder {{ row_class.next() }}">{{ folder|e }}</li>
- {% endfor %}
- {% for filename in files %}
- <li class="file {{ row_class.next() }}">{{ filename|e }}</li>
- {% endfor %}
- </ul>
-
- A cycler has the following attributes and methods:
-
- .. method:: reset()
-
- Resets the cycle to the first item.
-
- .. method:: next()
-
- Goes one item a head and returns the then current item.
-
- .. attribute:: current
-
- Returns the current item.
-
- **new in Jinja 2.1**
-
-.. class:: joiner(sep=', ')
-
- A tiny helper that can be use to "join" multiple sections. A joiner is
- passed a string and will return that string every time it's calld, except
- the first time in which situation it returns an empty string. You can
- use this to join things::
-
- {% set pipe = joiner("|") %}
- {% if categories %} {{ pipe() }}
- Categories: {{ categories|join(", ") }}
- {% endif %}
- {% if author %} {{ pipe() }}
- Author: {{ author() }}
- {% endif %}
- {% if can_edit %} {{ pipe() }}
- <a href="?action=edit">Edit</a>
- {% endif %}
-
- **new in Jinja 2.1**
-
-
-Extensions
-----------
-
-The following sections cover the built-in Jinja2 extensions that may be
-enabled by the application. The application could also provide further
-extensions not covered by this documentation. In that case there should
-be a separate document explaining the extensions.
-
-.. _i18n-in-templates:
-
-i18n
-~~~~
-
-If the i18n extension is enabled it's possible to mark parts in the template
-as translatable. To mark a section as translatable you can use `trans`::
-
- <p>{% trans %}Hello {{ user }}!{% endtrans %}</p>
-
-To translate a template expression --- say, using template filters or just
-accessing an attribute of an object --- you need to bind the expression to a
-name for use within the translation block::
-
- <p>{% trans user=user.username %}Hello {{ user }}!{% endtrans %}</p>
-
-If you need to bind more than one expression inside a `trans` tag, separate
-the pieces with a comma (``,``)::
-
- {% trans book_title=book.title, author=author.name %}
- This is {{ book_title }} by {{ author }}
- {% endtrans %}
-
-Inside trans tags no statements are allowed, only variable tags are.
-
-To pluralize, specify both the singular and plural forms with the `pluralize`
-tag, which appears between `trans` and `endtrans`::
-
- {% trans count=list|length %}
- There is {{ count }} {{ name }} object.
- {% pluralize %}
- There are {{ count }} {{ name }} objects.
- {% endtrans %}
-
-Per default the first variable in a block is used to determine the correct
-singular or plural form. If that doesn't work out you can specify the name
-which should be used for pluralizing by adding it as parameter to `pluralize`::
-
- {% trans ..., user_count=users|length %}...
- {% pluralize user_count %}...{% endtrans %}
-
-It's also possible to translate strings in expressions. For that purpose
-three functions exist:
-
-_ `gettext`: translate a single string
-- `ngettext`: translate a pluralizable string
-- `_`: alias for `gettext`
-
-For example you can print a translated string easily this way::
-
- {{ _('Hello World!') }}
-
-To use placeholders you can use the `format` filter::
-
- {{ _('Hello %(user)s!')|format(user=user.username) }}
- or
- {{ _('Hello %s')|format(user.username) }}
-
-For multiple placeholders always use keyword arguments to `format` as other
-languages may not use the words in the same order.
-
-
-Expression Statement
-~~~~~~~~~~~~~~~~~~~~
-
-If the expression-statement extension is loaded a tag called `do` is available
-that works exactly like the regular variable expression (``{{ ... }}``) just
-that it doesn't print anything. This can be used to modify lists::
-
- {% do navigation.append('a string') %}
-
-
-Loop Controls
-~~~~~~~~~~~~~
-
-If the application enables the :ref:`loopcontrols-extension` it's possible to
-use `break` and `continue` in loops. When `break` is reached, the loop is
-terminated, if `continue` is eached the processing is stopped and continues
-with the next iteration.
-
-Here a loop that skips every second item::
-
- {% for user in users %}
- {%- if loop.index is even %}{% continue %}{% endif %}
- ...
- {% endfor %}
-
-Likewise a look that stops processing after the 10th iteration::
-
- {% for user in users %}
- {%- if loop.index >= 10 %}{% break %}{% endif %}
- {%- endfor %}
-
-
-With Statement
-~~~~~~~~~~~~~~
-
-.. versionadded:: 2.3
-
-If the application enables the :ref:`with-extension` it is possible to
-use the `with` keyword in templates. This makes it possible to create
-a new inner scope. Variables set within this scope are not visible
-outside of the scope.
-
-With in a nutshell::
-
- {% with %}
- {% set foo = 42 %}
- {{ foo }} foo is 42 here
- {% endwith %}
- foo is not visible here any longer
-
-Because it is common to set variables at the beginning of the scope
-you can do that within the with statement. The following two examples
-are equivalent::
-
- {% with foo = 42 %}
- {{ foo }}
- {% endwith %}
-
- {% with %}
- {% set foo = 42 %}
- {{ foo }}
- {% endwith %}
--- a/bundled/jinja2/docs/tricks.rst Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-Tips and Tricks
-===============
-
-.. highlight:: html+jinja
-
-This part of the documentation shows some tips and tricks for Jinja2
-templates.
-
-
-.. _null-master-fallback:
-
-Null-Master Fallback
---------------------
-
-Jinja2 supports dynamic inheritance and does not distinguish between parent
-and child template as long as no `extends` tag is visited. While this leads
-to the surprising behavior that everything before the first `extends` tag
-including whitespace is printed out instead of being igored, it can be used
-for a neat trick.
-
-Usually child templates extend from one template that adds a basic HTML
-skeleton. However it's possible put the `extends` tag into an `if` tag to
-only extend from the layout template if the `standalone` variable evaluates
-to false which it does per default if it's not defined. Additionally a very
-basic skeleton is added to the file so that if it's indeed rendered with
-`standalone` set to `True` a very basic HTML skeleton is added::
-
- {% if not standalone %}{% extends 'master.html' %}{% endif -%}
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <title>{% block title %}The Page Title{% endblock %}</title>
- <link rel="stylesheet" href="style.css" type="text/css">
- {% block body %}
- <p>This is the page body.</p>
- {% endblock %}
-
-
-Alternating Rows
-----------------
-
-If you want to have different styles for each row of a table or
-list you can use the `cycle` method on the `loop` object::
-
- <ul>
- {% for row in rows %}
- <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
- {% endfor %}
- </ul>
-
-`cycle` can take an unlimited amount of strings. Each time this
-tag is encountered the next item from the list is rendered.
-
-
-Highlighting Active Menu Items
-------------------------------
-
-Often you want to have a navigation bar with an active navigation
-item. This is really simple to achieve. Because assignments outside
-of `block`\s in child templates are global and executed before the layout
-template is evaluated it's possible to define the active menu item in the
-child template::
-
- {% extends "layout.html" %}
- {% set active_page = "index" %}
-
-The layout template can then access `active_page`. Additionally it makes
-sense to defined a default for that variable::
-
- {% set navigation_bar = [
- ('/', 'index', 'Index'),
- ('/downloads/', 'downloads', 'Downloads'),
- ('/about/', 'about', 'About')
- ] -%}
- {% set active_page = active_page|default('index') -%}
- ...
- <ul id="navigation">
- {% for href, id, caption in navigation_bar %}
- <li{% if id == active_page %} class="active"{% endif
- %}><a href="{{ href|e }}">{{ caption|e }}</a>/li>
- {% endfor %}
- </ul>
- ...
-
-.. _accessing-the-parent-loop:
-
-Accessing the parent Loop
--------------------------
-
-The special `loop` variable always points to the innermost loop. If it's
-desired to have access to an outer loop it's possible to alias it::
-
- <table>
- {% for row in table %}
- <tr>
- {% set rowloop = loop %}
- {% for cell in row %}
- <td id="cell-{{ rowloop.index }}-{{ loop.index }}>{{ cell }}</td>
- {% endfor %}
- </tr>
- {% endfor %}
- </table>
--- a/bundled/jinja2/examples/basic/cycle.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-from jinja2 import Environment
-
-
-env = Environment(line_statement_prefix="#", variable_start_string="${", variable_end_string="}")
-
-
-print env.from_string("""\
-<ul>
-# for item in range(10)
- <li class="${loop.cycle('odd', 'even')}">${item}</li>
-# endfor
-</ul>\
-""").render()
--- a/bundled/jinja2/examples/basic/debugger.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-from jinja2 import Environment
-from jinja2.loaders import FileSystemLoader
-
-env = Environment(loader=FileSystemLoader('templates'))
-
-tmpl = env.get_template('broken.html')
-print tmpl.render(seq=[3, 2, 4, 5, 3, 2, 0, 2, 1])
--- a/bundled/jinja2/examples/basic/inheritance.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-from jinja2 import Environment
-from jinja2.loaders import DictLoader
-
-
-env = Environment(loader=DictLoader({
-'a': '''[A[{% block body %}{% endblock %}]]''',
-'b': '''{% extends 'a' %}{% block body %}[B]{% endblock %}''',
-'c': '''{% extends 'b' %}{% block body %}###{{ super() }}###{% endblock %}'''
-}))
-
-
-print env.get_template('c').render()
--- a/bundled/jinja2/examples/basic/templates/broken.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-{% from 'subbroken.html' import may_break %}
-<ul>
-{% for item in seq %}
- <li>{{ may_break(item) }}</li>
-{% endfor %}
-</ul>
--- a/bundled/jinja2/examples/basic/templates/subbroken.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-{% macro may_break(item) -%}
- [{{ item / 0 }}]
-{%- endmacro %}
--- a/bundled/jinja2/examples/basic/test.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-from jinja2 import Environment
-from jinja2.loaders import DictLoader
-
-env = Environment(loader=DictLoader({
-'child.html': u'''\
-{% extends master_layout or 'master.html' %}
-{% include helpers = 'helpers.html' %}
-{% macro get_the_answer() %}42{% endmacro %}
-{% title = 'Hello World' %}
-{% block body %}
- {{ get_the_answer() }}
- {{ helpers.conspirate() }}
-{% endblock %}
-''',
-'master.html': u'''\
-<!doctype html>
-<title>{{ title }}</title>
-{% block body %}{% endblock %}
-''',
-'helpers.html': u'''\
-{% macro conspirate() %}23{% endmacro %}
-'''
-}))
-
-
-tmpl = env.get_template("child.html")
-print tmpl.render()
--- a/bundled/jinja2/examples/basic/test_filter_and_linestatements.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-from jinja2 import Environment
-
-
-env = Environment(line_statement_prefix='%', variable_start_string="${", variable_end_string="}")
-tmpl = env.from_string("""\
-% macro foo()
- ${caller(42)}
-% endmacro
-<ul>
-% for item in seq
- <li>${item}</li>
-% endfor
-</ul>
-% call(var) foo()
- [${var}]
-% endcall
-% filter escape
- <hello world>
- % for item in [1, 2, 3]
- - ${item}
- % endfor
-% endfilter
-""")
-
-print tmpl.render(seq=range(10))
--- a/bundled/jinja2/examples/basic/test_loop_filter.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-from jinja2 import Environment
-
-tmpl = Environment().from_string("""\
-<ul>
-{%- for item in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] if item % 2 == 0 %}
- <li>{{ loop.index }} / {{ loop.length }}: {{ item }}</li>
-{%- endfor %}
-</ul>
-if condition: {{ 1 if foo else 0 }}
-""")
-
-print tmpl.render(foo=True)
--- a/bundled/jinja2/examples/basic/translate.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-from jinja2 import Environment
-
-print Environment(extensions=['jinja2.i18n.TransExtension']).from_string("""\
-{% trans %}Hello {{ user }}!{% endtrans %}
-{% trans count=users|count %}{{ count }} user{% pluralize %}{{ count }} users{% endtrans %}
-""").render(user="someone")
--- a/bundled/jinja2/examples/bench.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,361 +0,0 @@
-"""\
- This benchmark compares some python templating engines with Jinja 2 so
- that we get a picture of how fast Jinja 2 is for a semi real world
- template. If a template engine is not installed the test is skipped.\
-"""
-import sys
-import cgi
-from timeit import Timer
-from jinja2 import Environment as JinjaEnvironment
-
-context = {
- 'page_title': 'mitsuhiko\'s benchmark',
- 'table': [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)]
-}
-
-jinja_template = JinjaEnvironment(
- line_statement_prefix='%',
- variable_start_string="${",
- variable_end_string="}"
-).from_string("""\
-<!doctype html>
-<html>
- <head>
- <title>${page_title|e}</title>
- </head>
- <body>
- <div class="header">
- <h1>${page_title|e}</h1>
- </div>
- <ul class="navigation">
- % for href, caption in [
- ('index.html', 'Index'),
- ('downloads.html', 'Downloads'),
- ('products.html', 'Products')
- ]
- <li><a href="${href|e}">${caption|e}</a></li>
- % endfor
- </ul>
- <div class="table">
- <table>
- % for row in table
- <tr>
- % for cell in row
- <td>${cell}</td>
- % endfor
- </tr>
- % endfor
- </table>
- </div>
- </body>
-</html>\
-""")
-
-def test_jinja():
- jinja_template.render(context)
-
-try:
- from tornado.template import Template
-except ImportError:
- test_tornado = None
-else:
- tornado_template = Template("""\
-<!doctype html>
-<html>
- <head>
- <title>{{ page_title }}</title>
- </head>
- <body>
- <div class="header">
- <h1>{{ page_title }}</h1>
- </div>
- <ul class="navigation">
- {% for href, caption in [ \
- ('index.html', 'Index'), \
- ('downloads.html', 'Downloads'), \
- ('products.html', 'Products') \
- ] %}
- <li><a href="{{ href }}">{{ caption }}</a></li>
- {% end %}
- </ul>
- <div class="table">
- <table>
- {% for row in table %}
- <tr>
- {% for cell in row %}
- <td>{{ cell }}</td>
- {% end %}
- </tr>
- {% end %}
- </table>
- </div>
- </body>
-</html>\
-""")
-
- def test_tornado():
- tornado_template.generate(**context)
-
-try:
- from django.conf import settings
- settings.configure()
- from django.template import Template as DjangoTemplate, Context as DjangoContext
-except ImportError:
- test_django = None
-else:
- django_template = """\
-<!doctype html>
-<html>
- <head>
- <title>{{ page_title }}</title>
- </head>
- <body>
- <div class="header">
- <h1>{{ page_title }}</h1>
- </div>
- <ul class="navigation">
- {% for href, caption in navigation %}
- <li><a href="{{ href }}">{{ caption }}</a></li>
- {% endfor %}
- </ul>
- <div class="table">
- <table>
- {% for row in table %}
- <tr>
- {% for cell in row %}
- <td>{{ cell }}</td>
- {% endfor %}
- </tr>
- {% endfor %}
- </table>
- </div>
- </body>
-</html>\
-"""
-
- def test_django():
- c = DjangoContext(context)
- c['navigation'] = [('index.html', 'Index'), ('downloads.html', 'Downloads'),
- ('products.html', 'Products')]
- # recompile template each rendering because that's what django
- # is doing in normal situations too. Django is not thread safe
- # so we can't cache it in regular apps either.
- DjangoTemplate(django_template).render(c)
-
-try:
- from mako.template import Template as MakoTemplate
-except ImportError:
- test_mako = None
-else:
- mako_template = MakoTemplate("""\
-<!doctype html>
-<html>
- <head>
- <title>${page_title|h}</title>
- </head>
- <body>
- <div class="header">
- <h1>${page_title|h}</h1>
- </div>
- <ul class="navigation">
- % for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
- <li><a href="${href|h}">${caption|h}</a></li>
- % endfor
- </ul>
- <div class="table">
- <table>
- % for row in table:
- <tr>
- % for cell in row:
- <td>${cell}</td>
- % endfor
- </tr>
- % endfor
- </table>
- </div>
- </body>
-</html>\
-""")
-
- def test_mako():
- mako_template.render(**context)
-
-try:
- from genshi.template import MarkupTemplate as GenshiTemplate
-except ImportError:
- test_genshi = None
-else:
- genshi_template = GenshiTemplate("""\
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
- <head>
- <title>${page_title}</title>
- </head>
- <body>
- <div class="header">
- <h1>${page_title}</h1>
- </div>
- <ul class="navigation">
- <li py:for="href, caption in [
- ('index.html', 'Index'),
- ('downloads.html', 'Downloads'),
- ('products.html', 'Products')]"><a href="${href}">${caption}</a></li>
- </ul>
- <div class="table">
- <table>
- <tr py:for="row in table">
- <td py:for="cell in row">${cell}</td>
- </tr>
- </table>
- </div>
- </body>
-</html>\
-""")
-
- def test_genshi():
- genshi_template.generate(**context).render('html', strip_whitespace=False)
-
-try:
- from Cheetah.Template import Template as CheetahTemplate
-except ImportError:
- test_cheetah = None
-else:
- cheetah_template = CheetahTemplate("""\
-#import cgi
-<!doctype html>
-<html>
- <head>
- <title>$cgi.escape($page_title)</title>
- </head>
- <body>
- <div class="header">
- <h1>$cgi.escape($page_title)</h1>
- </div>
- <ul class="navigation">
- #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
- <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
- #end for
- </ul>
- <div class="table">
- <table>
- #for $row in $table:
- <tr>
- #for $cell in $row:
- <td>$cell</td>
- #end for
- </tr>
- #end for
- </table>
- </div>
- </body>
-</html>\
-""", searchList=[dict(context)])
-
- def test_cheetah():
- unicode(cheetah_template)
-
-try:
- import tenjin
-except ImportError:
- test_tenjin = None
-else:
- tenjin_template = tenjin.Template()
- tenjin_template.convert("""\
-<!doctype html>
-<html>
- <head>
- <title>${page_title}</title>
- </head>
- <body>
- <div class="header">
- <h1>${page_title}</h1>
- </div>
- <ul class="navigation">
-<?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]: ?>
- <li><a href="${href}">${caption}</a></li>
-<?py #end ?>
- </ul>
- <div class="table">
- <table>
-<?py for row in table: ?>
- <tr>
-<?py for cell in row: ?>
- <td>#{cell}</td>
-<?py #end ?>
- </tr>
-<?py #end ?>
- </table>
- </div>
- </body>
-</html>\
-""")
-
- def test_tenjin():
- from tenjin.helpers import escape, to_str
- tenjin_template.render(context, locals())
-
-try:
- from spitfire.compiler import util as SpitfireTemplate
- from spitfire.compiler.analyzer import o2_options as spitfire_optimizer
-except ImportError:
- test_spitfire = None
-else:
- spitfire_template = SpitfireTemplate.load_template("""\
-<!doctype html>
-<html>
- <head>
- <title>$cgi.escape($page_title)</title>
- </head>
- <body>
- <div class="header">
- <h1>$cgi.escape($page_title)</h1>
- </div>
- <ul class="navigation">
- #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]
- <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
- #end for
- </ul>
- <div class="table">
- <table>
- #for $row in $table
- <tr>
- #for $cell in $row
- <td>$cell</td>
- #end for
- </tr>
- #end for
- </table>
- </div>
- </body>
-</html>\
-""", 'spitfire_tmpl', spitfire_optimizer, {'enable_filters': False})
- spitfire_context = dict(context, **{'cgi': cgi})
-
- def test_spitfire():
- spitfire_template(search_list=[spitfire_context]).main()
-
-sys.stdout.write('\r' + '\n'.join((
- '=' * 80,
- 'Template Engine BigTable Benchmark'.center(80),
- '=' * 80,
- __doc__,
- '-' * 80
-)) + '\n')
-
-
-for test in 'jinja', 'mako', 'tornado', 'tenjin', 'spitfire', 'django', 'genshi', 'cheetah':
- if locals()['test_' + test] is None:
- sys.stdout.write(' %-20s*not installed*\n' % test)
- continue
- t = Timer(setup='from __main__ import test_%s as bench' % test,
- stmt='bench()')
- sys.stdout.write(' >> %-20s<running>' % test)
- sys.stdout.flush()
- sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=50) / 50))
-sys.stdout.write('-' * 80 + '\n')
-sys.stdout.write('''\
- WARNING: The results of this benchmark are useless to compare the
- performance of template engines and should not be taken seriously in any
- way. It's testing the performance of simple loops and has no real-world
- usefulnes. It only used to check if changes on the Jinja code affect
- performance in a good or bad way and how it roughly compares to others.
-''' + '=' * 80 + '\n')
--- a/bundled/jinja2/examples/profile.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-try:
- from cProfile import Profile
-except ImportError:
- from profile import Profile
-from pstats import Stats
-from jinja2 import Environment as JinjaEnvironment
-
-context = {
- 'page_title': 'mitsuhiko\'s benchmark',
- 'table': [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)]
-}
-
-source = """\
-<!doctype html>
-<html>
- <head>
- <title>${page_title|e}</title>
- </head>
- <body>
- <div class="header">
- <h1>${page_title|e}</h1>
- </div>
- <div class="table">
- <table>
- % for row in table
- <tr>
- % for cell in row
- <td>${cell}</td>
- % endfor
- </tr>
- % endfor
- </table>
- </div>
- </body>
-</html>\
-"""
-jinja_template = JinjaEnvironment(
- line_statement_prefix='%',
- variable_start_string="${",
- variable_end_string="}"
-).from_string(source)
-print jinja_template.environment.compile(source, raw=True)
-
-
-p = Profile()
-p.runcall(lambda: jinja_template.render(context))
-stats = Stats(p)
-stats.sort_stats('time', 'calls')
-stats.print_stats()
--- a/bundled/jinja2/examples/rwbench/django/_form.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-<form action="{{ action }}" method="{{ method }}">{{ body }}</form>
--- a/bundled/jinja2/examples/rwbench/django/_input_field.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-<input type="{{ type }}" value="{{ value }}" name="{{ name }}">
--- a/bundled/jinja2/examples/rwbench/django/_textarea.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-<textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols }}">{{ value }}</textarea>
--- a/bundled/jinja2/examples/rwbench/django/index.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-{% extends "layout.html" %}
-{% block page_title %}Index Page{% endblock %}
-{% block body %}
- {% for article in articles %}
- {% if article.published %}
- <div class="article">
- <h2><a href="{{ article.href }}">{{ article.title }}</a></h2>
- <p class="meta">written by <a href="{{ article.user.href }}">{{ article.user.username }}</a> on {{ article.pub_date|dateformat }}</p>
- <div class="text">{{ article.body|safe }}</div>
- </div>
- {% endif %}
- {% endfor %}
- {% form %}
- <dl>
- <dt>Name</dt>
- <dd>{% input_field 'name' %}</dd>
- <dt>E-Mail</dt>
- <dd>{% input_field 'email' %}</dd>
- <dt>URL</dt>
- <dd>{% input_field 'url' %}</dd>
- <dt>Comment</dt>
- <dd>{% textarea 'comment' %}</dd>
- <dt>Captcha</dt>
- <dd>{% input_field 'captcha' %}</dd>
- </dl>
- {% input_field '' 'submit' 'Submit' %}
- {% input_field 'cancel' 'submit' 'Cancel' %}
- {% endform %}
-{% endblock %}
--- a/bundled/jinja2/examples/rwbench/django/layout.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <title>{% block page_title %}{% endblock %} | RealWorld Benchmark</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-</head>
-<body>
- <div class="contents">
- <div class="header">
- <h1>RealWorld Benchmark</h1>
- <blockquote><p>
- A less stupid benchmark for Mako and Jinja2 to get an impression how
- code changes affect runtime performance.
- </p></blockquote>
- </div>
- <ul class="navigation">
- {% for href, caption in page_navigation %}
- <li><a href="{{ href }}">{{ caption }}</a></li>
- {% endfor %}
- </ul>
- <div class="body">
- {% block body %}{% endblock %}
- </div>
- <div class="footer">
- © Copyright 2008 by I don't know who.
- </div>
- </div>
-</body>
-</html>
--- a/bundled/jinja2/examples/rwbench/djangoext.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-from rwbench import ROOT
-from os.path import join
-from django.conf import settings
-settings.configure(TEMPLATE_DIRS=(join(ROOT, 'django'),))
-from django.template import loader as django_loader, Context as DjangoContext, \
- Node, NodeList, Variable, TokenParser
-from django import template as django_template_module
-from django.template import Library
-
-
-# for django extensions. We monkey patch our extensions in so that
-# we don't have to initialize a more complex django setup.
-django_extensions = django_template_module.Library()
-django_template_module.builtins.append(django_extensions)
-
-
-from rwbench import dateformat
-django_extensions.filter(dateformat)
-
-
-def var_or_none(x):
- if x is not None:
- return Variable(x)
-
-
-# and more django extensions
-@django_extensions.tag
-def input_field(parser, token):
- p = TokenParser(token.contents)
- args = [p.value()]
- while p.more():
- args.append(p.value())
- return InputFieldNode(*args)
-
-
-@django_extensions.tag
-def textarea(parser, token):
- p = TokenParser(token.contents)
- args = [p.value()]
- while p.more():
- args.append(p.value())
- return TextareaNode(*args)
-
-
-@django_extensions.tag
-def form(parser, token):
- p = TokenParser(token.contents)
- args = []
- while p.more():
- args.append(p.value())
- body = parser.parse(('endform',))
- parser.delete_first_token()
- return FormNode(body, *args)
-
-
-class InputFieldNode(Node):
-
- def __init__(self, name, type=None, value=None):
- self.name = var_or_none(name)
- self.type = var_or_none(type)
- self.value = var_or_none(value)
-
- def render(self, context):
- name = self.name.resolve(context)
- type = 'text'
- value = ''
- if self.type is not None:
- type = self.type.resolve(context)
- if self.value is not None:
- value = self.value.resolve(context)
- tmpl = django_loader.get_template('_input_field.html')
- return tmpl.render(DjangoContext({
- 'name': name,
- 'type': type,
- 'value': value
- }))
-
-
-class TextareaNode(Node):
-
- def __init__(self, name, rows=None, cols=None, value=None):
- self.name = var_or_none(name)
- self.rows = var_or_none(rows)
- self.cols = var_or_none(cols)
- self.value = var_or_none(value)
-
- def render(self, context):
- name = self.name.resolve(context)
- rows = 10
- cols = 40
- value = ''
- if self.rows is not None:
- rows = int(self.rows.resolve(context))
- if self.cols is not None:
- cols = int(self.cols.resolve(context))
- if self.value is not None:
- value = self.value.resolve(context)
- tmpl = django_loader.get_template('_textarea.html')
- return tmpl.render(DjangoContext({
- 'name': name,
- 'rows': rows,
- 'cols': cols,
- 'value': value
- }))
-
-
-class FormNode(Node):
-
- def __init__(self, body, action=None, method=None):
- self.body = body
- self.action = action
- self.method = method
-
- def render(self, context):
- body = self.body.render(context)
- action = ''
- method = 'post'
- if self.action is not None:
- action = self.action.resolve(context)
- if self.method is not None:
- method = self.method.resolve(context)
- tmpl = django_loader.get_template('_form.html')
- return tmpl.render(DjangoContext({
- 'body': body,
- 'action': action,
- 'method': method
- }))
--- a/bundled/jinja2/examples/rwbench/genshi/helpers.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-<div xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/"
- py:strip="">
-
- <py:def function="input_field(name='', value='', type='text')">
- <input type="$type" value="$value" name="$name" />
- </py:def>
-
- <py:def function="textarea(name, value='', rows=10, cols=40)">
- <textarea name="$name" rows="$rows" cols="cols">$value</textarea>
- </py:def>
-
-</div>
--- a/bundled/jinja2/examples/rwbench/genshi/index.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-<?python
- from rwbench import dateformat
-?>
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="layout.html" />
- <xi:include href="helpers.html" />
- <head><title>Index Page</title></head>
- <body>
- <div class="article" py:for="article in articles">
- <py:if test="article.published">
- <h2><a href="${article.href}">${article.title}</a></h2>
- <p class="meta">written by <a href="${article.user.href}"
- >${article.user.username}</a> on ${dateformat(article.pub_date)}</p>
- <div class="text">${Markup(article.body)}</div>
- </py:if>
- </div>
- <!--
- For a fair and balanced comparison we would have to use a def here
- that wraps the form data but I don't know what would be the best
- Genshi equivalent for that. Quite frankly I doubt that this makes
- sense in Genshi anyways.
- -->
- <form action="" method="post">
- <dl>
- <dt>Name</dt>
- <dd>${input_field('name')}</dd>
- <dt>E-Mail</dt>
- <dd>${input_field('email')}</dd>
- <dt>URL</dt>
- <dd>${input_field('url')}</dd>
- <dt>Comment</dt>
- <dd>${textarea('comment')}</dd>
- <dt>Captcha</dt>
- <dd>${input_field('captcha')}</dd>
- </dl>
- ${input_field(type='submit', value='Submit')}
- ${input_field(name='cancel', type='submit', value='Cancel')}
- </form>
- </body>
-</html>
--- a/bundled/jinja2/examples/rwbench/genshi/layout.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" >
- <py:match path="head" once="true">
- <head>
- <title>${select('title/text()')} | RealWorld Benchmark</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- </head>
- </py:match>
- <py:match path="body" once="true">
- <body>
- <div class="contents">
- <div class="header">
- <h1>RealWorld Benchmark</h1>
- <blockquote><p>
- A less stupid benchmark for Mako and Jinja2 to get an impression how
- code changes affect runtime performance.
- </p></blockquote>
- </div>
- <ul class="navigation">
- <li py:for="href, caption in page_navigation"><a href="$href">$caption</a></li>
- </ul>
- <div class="body">
- ${select('*|text()')}
- </div>
- <div class="footer">
- © Copyright 2008 by I don't know who.
- </div>
- </div>
- </body>
- </py:match>
-</html>
--- a/bundled/jinja2/examples/rwbench/jinja/helpers.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-{% macro input_field(name, value='', type='text') -%}
- <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
-{%- endmacro %}
-
-{% macro textarea(name, value='', rows=10, cols=40) -%}
- <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols }}">{{
- value|e }}</textarea>
-{%- endmacro %}
-
-{% macro form(action='', method='post') -%}
- <form action="{{ action|e }}" method="{{ method }}">{{ caller() }}</form>
-{%- endmacro %}
--- a/bundled/jinja2/examples/rwbench/jinja/index.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-{% extends "layout.html" %}
-{% from "helpers.html" import input_field, textarea, form %}
-{% block page_title %}Index Page{% endblock %}
-{% block body %}
- {%- for article in articles if article.published %}
- <div class="article">
- <h2><a href="{{ article.href|e }}">{{ article.title|e }}</a></h2>
- <p class="meta">written by <a href="{{ article.user.href|e
- }}">{{ article.user.username|e }}</a> on {{ article.pub_date|dateformat }}</p>
- <div class="text">{{ article.body }}</div>
- </div>
- {%- endfor %}
- {%- call form() %}
- <dl>
- <dt>Name</dt>
- <dd>{{ input_field('name') }}</dd>
- <dt>E-Mail</dt>
- <dd>{{ input_field('email') }}</dd>
- <dt>URL</dt>
- <dd>{{ input_field('url') }}</dd>
- <dt>Comment</dt>
- <dd>{{ textarea('comment') }}</dd>
- <dt>Captcha</dt>
- <dd>{{ input_field('captcha') }}</dd>
- </dl>
- {{ input_field(type='submit', value='Submit') }}
- {{ input_field('cancel', type='submit', value='Cancel') }}
- {%- endcall %}
-{% endblock %}
--- a/bundled/jinja2/examples/rwbench/jinja/layout.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <title>{% block page_title %}{% endblock %} | RealWorld Benchmark</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-</head>
-<body>
- <div class="contents">
- <div class="header">
- <h1>RealWorld Benchmark</h1>
- <blockquote><p>
- A less stupid benchmark for Mako and Jinja2 to get an impression how
- code changes affect runtime performance.
- </p></blockquote>
- </div>
- <ul class="navigation">
- {%- for href, caption in page_navigation %}
- <li><a href="{{ href|e }}">{{ caption }}</a></li>
- {%- endfor %}
- </ul>
- <div class="body">
- {% block body %}{% endblock %}
- </div>
- <div class="footer">
- © Copyright 2008 by I don't know who.
- </div>
- </div>
-</body>
-</html>
--- a/bundled/jinja2/examples/rwbench/mako/helpers.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-<%def name="input_field(name='', value='', type='text')">
- <input type="${type}" value="${value|h}" name="${name}">
-</%def>
-
-<%def name="textarea(name, value='', rows=10, cols=40)">
- <textarea name="${name}" rows="${rows}" cols="${cols}">${value|h}</textarea>
-</%def>
-
-<%def name="form(action='', method='post')">
- <form action="${action|h}" method="${method}">${caller.body()}</form>
-</%def>
--- a/bundled/jinja2/examples/rwbench/mako/index.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-<%!
- from rwbench import dateformat
-%>
-<%inherit file="layout.html" />
-<%namespace file="helpers.html" import="input_field, textarea, form" />
-<%def name="page_title()">Index Page</%def>
-% for article in articles:
- <% if not article.published: continue %>
-<div class="article">
- <h2><a href="${article.href|h}">${article.title|h}</a></h2>
- <p class="meta">written by <a href="${article.user.href|h
- }">${article.user.username|h}</a> on ${dateformat(article.pub_date)}</p>
- <div class="text">${article.body}</div>
-</div>
-% endfor
-<%call expr="form()">
- <dl>
- <dt>Name</dt>
- <dd>${input_field('name')}</dd>
- <dt>E-Mail</dt>
- <dd>${input_field('email')}</dd>
- <dt>URL</dt>
- <dd>${input_field('url')}</dd>
- <dt>Comment</dt>
- <dd>${textarea('comment')}</dd>
- <dt>Captcha</dt>
- <dd>${input_field('captcha')}</dd>
- </dl>
- ${input_field(type='submit', value='Submit')}
- ${input_field(name='cancel', type='submit', value='Cancel')}
-</%call>
--- a/bundled/jinja2/examples/rwbench/mako/layout.html Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <title>${self.page_title()} | RealWorld Benchmark</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-</head>
-<body>
- <div class="contents">
- <div class="header">
- <h1>RealWorld Benchmark</h1>
- <blockquote><p>
- A less stupid benchmark for Mako and Jinja2 to get an impression how
- code changes affect runtime performance.
- </p></blockquote>
- </div>
- <ul class="navigation">
- % for href, caption in page_navigation:
- <li><a href="${href|h}">${caption}</a></li>
- % endfor
- </ul>
- <div class="body">
- ${self.body()}
- </div>
- <div class="footer">
- © Copyright 2008 by I don't know who.
- </div>
- </div>
-</body>
-</html>
-<%def name="page_title()"></%def>
--- a/bundled/jinja2/examples/rwbench/rwbench.py Fri Jun 11 20:14:01 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- RealWorldish Benchmark
- ~~~~~~~~~~~~~~~~~~~~~~
-
- A more real-world benchmark of Jinja2. Like the other benchmark in the
- Jinja2 repository this has no real-world usefulnes (despite the name).
- Just go away and ignore it. NOW!
-
- :copyright: (c) 2009 by the Jinja Team.
- :license: BSD.
-"""
-import sys
-from os.path import join, dirname, abspath
-ROOT = abspath(dirname(__file__))
-
-from random import choice, randrange
-from datetime import datetime
-from timeit import Timer
-from jinja2 import Environment, FileSystemLoader
-from jinja2.utils import generate_lorem_ipsum
-from mako.lookup import TemplateLookup
-from genshi.template import TemplateLoader as GenshiTemplateLoader
-
-
-def dateformat(x):
- return x.strftime('%Y-%m-%d')
-
-
-jinja_env = Environment(loader=FileSystemLoader(join(ROOT, 'jinja')))
-jinja_env.filters['dateformat'] = dateformat
-mako_lookup = TemplateLookup(directories=[join(ROOT, 'mako')])
-genshi_loader = GenshiTemplateLoader([join(ROOT, 'genshi')])
-
-class Article(object):
-
- def __init__(self, id):
- self.id = id
- self.href = '/article/%d' % self.id
- self.title = generate_lorem_ipsum(1, False, 5, 10)
- self.user = choice(users)
- self.body = generate_lorem_ipsum()
- self.pub_date = datetime.utcfromtimestamp(randrange(10 ** 9, 2 * 10 ** 9))
- self.published = True
-
-
-class User(object):
-
- def __init__(self, username):
- self.href = '/user/%s' % username
- self.username = username
-
-
-users = map(User, [u'John Doe', u'Jane Doe', u'Peter Somewhat'])
-articles = map(Article, range(20))
-navigation = [
- ('index', 'Index'),
- ('about', 'About'),
- ('foo?bar=1', 'Foo with Bar'),
- ('foo?bar=2&s=x', 'Foo with X'),
- ('blah', 'Blub Blah'),
- ('hehe', 'Haha'),
-] * 5
-
-context = dict(users=users, articles=articles, page_navigation=navigation)
-
-
-jinja_template = jinja_env.get_template('index.html')
-mako_template = mako_lookup.get_template('index.html')
-genshi_template = genshi_loader.load('index.html')
-
-
-def test_jinja():
- jinja_template.render(context)
-
-def test_mako():
- mako_template.render_unicode(**context)
-
-
-from djangoext import django_loader, DjangoContext
-def test_django():
- # not cached because django is not thread safe and does
- # not cache by itself so it would be unfair to cache it here.
- django_template = django_loader.get_template('index.html')
- django_template.render(DjangoContext(context))
-
-
-def test_genshi():
- genshi_template.generate(**context).render('html', doctype='html')
-
-
-if __name__ == '__main__':
- sys.stdout.write('Realworldish Benchmark:\n')
- for test in 'jinja', 'mako', 'django', 'genshi':
- t = Timer(setup='from __main__ import test_%s as bench' % test,
- stmt='bench()')
- sys.stdout.write(' >> %-20s<running>' % test)
- sys.stdout.flush()
- sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=200) / 200))
--- a/bundled/jinja2/jinja2/__init__.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/__init__.py Fri Jun 11 20:32:12 2010 -0400
@@ -38,7 +38,8 @@
# loaders
from jinja2.loaders import BaseLoader, FileSystemLoader, PackageLoader, \
- DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader
+ DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader, \
+ ModuleLoader
# bytecode caches
from jinja2.bccache import BytecodeCache, FileSystemBytecodeCache, \
@@ -53,9 +54,11 @@
TemplateAssertionError
# decorators and public utilities
-from jinja2.filters import environmentfilter, contextfilter
+from jinja2.filters import environmentfilter, contextfilter, \
+ evalcontextfilter
from jinja2.utils import Markup, escape, clear_caches, \
- environmentfunction, contextfunction, is_undefined
+ environmentfunction, evalcontextfunction, contextfunction, \
+ is_undefined
__all__ = [
'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
@@ -64,6 +67,7 @@
'MemcachedBytecodeCache', 'Undefined', 'DebugUndefined',
'StrictUndefined', 'TemplateError', 'UndefinedError', 'TemplateNotFound',
'TemplatesNotFound', 'TemplateSyntaxError', 'TemplateAssertionError',
- 'environmentfilter', 'contextfilter', 'Markup', 'escape',
- 'environmentfunction', 'contextfunction', 'clear_caches', 'is_undefined'
+ 'ModuleLoader', 'environmentfilter', 'contextfilter', 'Markup', 'escape',
+ 'environmentfunction', 'contextfunction', 'clear_caches', 'is_undefined',
+ 'evalcontextfilter', 'evalcontextfunction'
]
--- a/bundled/jinja2/jinja2/compiler.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/compiler.py Fri Jun 11 20:32:12 2010 -0400
@@ -12,6 +12,7 @@
from itertools import chain
from copy import deepcopy
from jinja2 import nodes
+from jinja2.nodes import EvalContext
from jinja2.visitor import NodeVisitor, NodeTransformer
from jinja2.exceptions import TemplateAssertionError
from jinja2.utils import Markup, concat, escape, is_python_keyword, next
@@ -53,11 +54,12 @@
unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
-def generate(node, environment, name, filename, stream=None):
+def generate(node, environment, name, filename, stream=None,
+ defer_init=False):
"""Generate the python source for a node tree."""
if not isinstance(node, nodes.Template):
raise TypeError('Can\'t compile non template nodes')
- generator = CodeGenerator(environment, name, filename, stream)
+ generator = CodeGenerator(environment, name, filename, stream, defer_init)
generator.visit(node)
if stream is None:
return generator.stream.getvalue()
@@ -140,7 +142,8 @@
class Frame(object):
"""Holds compile time information for us."""
- def __init__(self, parent=None):
+ def __init__(self, eval_ctx, parent=None):
+ self.eval_ctx = eval_ctx
self.identifiers = Identifiers()
# a toplevel frame is the root + soft frames such as if conditions.
@@ -210,7 +213,7 @@
def inner(self):
"""Return an inner frame."""
- return Frame(self)
+ return Frame(self.eval_ctx, self)
def soft(self):
"""Return a soft frame. A soft frame may not be modified as
@@ -290,8 +293,7 @@
self.visit(node.test)
real_identifiers = self.identifiers
- old_names = real_identifiers.declared | \
- real_identifiers.declared_locally | \
+ old_names = real_identifiers.declared_locally | \
real_identifiers.declared_parameter
def inner_visit(nodes):
@@ -312,7 +314,8 @@
# the differences between the two branches are also pulled as
# undeclared variables
- real_identifiers.undeclared.update(body.symmetric_difference(else_))
+ real_identifiers.undeclared.update(body.symmetric_difference(else_) -
+ real_identifiers.declared)
# remember those that are declared.
real_identifiers.declared_locally.update(body | else_)
@@ -365,7 +368,8 @@
class CodeGenerator(NodeVisitor):
- def __init__(self, environment, name, filename, stream=None):
+ def __init__(self, environment, name, filename, stream=None,
+ defer_init=False):
if stream is None:
stream = StringIO()
self.environment = environment
@@ -373,6 +377,7 @@
self.filename = filename
self.stream = stream
self.created_block_context = False
+ self.defer_init = defer_init
# aliases for imports
self.import_aliases = {}
@@ -419,7 +424,7 @@
# -- Various compilation helpers
def fail(self, msg, lineno):
- """Fail with a `TemplateAssertionError`."""
+ """Fail with a :exc:`TemplateAssertionError`."""
raise TemplateAssertionError(msg, lineno, self.name, self.filename)
def temporary_identifier(self):
@@ -434,7 +439,16 @@
def return_buffer_contents(self, frame):
"""Return the buffer contents of the frame."""
- if self.environment.autoescape:
+ if frame.eval_ctx.volatile:
+ self.writeline('if context.eval_ctx.autoescape:')
+ self.indent()
+ self.writeline('return Markup(concat(%s))' % frame.buffer)
+ self.outdent()
+ self.writeline('else:')
+ self.indent()
+ self.writeline('return concat(%s)' % frame.buffer)
+ self.outdent()
+ elif frame.eval_ctx.autoescape:
self.writeline('return Markup(concat(%s))' % frame.buffer)
else:
self.writeline('return concat(%s)' % frame.buffer)
@@ -747,12 +761,18 @@
def visit_Template(self, node, frame=None):
assert frame is None, 'no root frame allowed'
+ eval_ctx = EvalContext(self.environment, self.name)
+
from jinja2.runtime import __all__ as exported
self.writeline('from __future__ import division')
self.writeline('from jinja2.runtime import ' + ', '.join(exported))
if not unoptimize_before_dead_code:
self.writeline('dummy = lambda *x: None')
+ # if we want a deferred initialization we cannot move the
+ # environment into a local name
+ envenv = not self.defer_init and ', environment=environment' or ''
+
# do we have an extends tag at all? If not, we can save some
# overhead by just not processing any inheritance code.
have_extends = node.find(nodes.Extends) is not None
@@ -779,10 +799,10 @@
self.writeline('name = %r' % self.name)
# generate the root render function.
- self.writeline('def root(context, environment=environment):', extra=1)
+ self.writeline('def root(context%s):' % envenv, extra=1)
# process the root
- frame = Frame()
+ frame = Frame(eval_ctx)
frame.inspect(node.body)
frame.toplevel = frame.rootlevel = True
frame.require_output_check = have_extends and not self.has_known_extends
@@ -811,11 +831,11 @@
# at this point we now have the blocks collected and can visit them too.
for name, block in self.blocks.iteritems():
- block_frame = Frame()
+ block_frame = Frame(eval_ctx)
block_frame.inspect(block.body)
block_frame.block = name
- self.writeline('def block_%s(context, environment=environment):'
- % name, block, 1)
+ self.writeline('def block_%s(context%s):' % (name, envenv),
+ block, 1)
self.indent()
undeclared = find_undeclared(block.body, ('self', 'super'))
if 'self' in undeclared:
@@ -1217,12 +1237,15 @@
body = []
for child in node.nodes:
try:
- const = child.as_const()
+ const = child.as_const(frame.eval_ctx)
except nodes.Impossible:
body.append(child)
continue
+ # the frame can't be volatile here, becaus otherwise the
+ # as_const() function would raise an Impossible exception
+ # at that point.
try:
- if self.environment.autoescape:
+ if frame.eval_ctx.autoescape:
if hasattr(const, '__html__'):
const = const.__html__()
else:
@@ -1260,7 +1283,10 @@
else:
self.newline(item)
close = 1
- if self.environment.autoescape:
+ if frame.eval_ctx.volatile:
+ self.write('(context.eval_ctx.autoescape and'
+ ' escape or to_string)(')
+ elif frame.eval_ctx.autoescape:
self.write('escape(')
else:
self.write('to_string(')
@@ -1293,7 +1319,11 @@
for argument in arguments:
self.newline(argument)
close = 0
- if self.environment.autoescape:
+ if frame.eval_ctx.volatile:
+ self.write('(context.eval_ctx.autoescape and'
+ ' escape or to_string)(')
+ close += 1
+ elif frame.eval_ctx.autoescape:
self.write('escape(')
close += 1
if self.environment.finalize is not None:
@@ -1360,7 +1390,11 @@
self.write(repr(val))
def visit_TemplateData(self, node, frame):
- self.write(repr(node.as_const()))
+ try:
+ self.write(repr(node.as_const(frame.eval_ctx)))
+ except nodes.Impossible:
+ self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)'
+ % node.data)
def visit_Tuple(self, node, frame):
self.write('(')
@@ -1420,8 +1454,14 @@
del binop, uaop
def visit_Concat(self, node, frame):
- self.write('%s((' % (self.environment.autoescape and
- 'markup_join' or 'unicode_join'))
+ if frame.eval_ctx.volatile:
+ func_name = '(context.eval_ctx.volatile and' \
+ ' markup_join or unicode_join)'
+ elif frame.eval_ctx.autoescape:
+ func_name = 'markup_join'
+ else:
+ func_name = 'unicode_join'
+ self.write('%s((' % func_name)
for arg in node.nodes:
self.visit(arg, frame)
self.write(', ')
@@ -1472,6 +1512,8 @@
self.fail('no filter named %r' % node.name, node.lineno)
if getattr(func, 'contextfilter', False):
self.write('context, ')
+ elif getattr(func, 'evalcontextfilter', False):
+ self.write('context.eval_ctx, ')
elif getattr(func, 'environmentfilter', False):
self.write('environment, ')
@@ -1479,7 +1521,11 @@
# and want to write to the current buffer
if node.node is not None:
self.visit(node.node, frame)
- elif self.environment.autoescape:
+ elif frame.eval_ctx.volatile:
+ self.write('(context.eval_ctx.autoescape and'
+ ' Markup(concat(%s)) or concat(%s))' %
+ (frame.buffer, frame.buffer))
+ elif frame.eval_ctx.autoescape:
self.write('Markup(concat(%s))' % frame.buffer)
else:
self.write('concat(%s)' % frame.buffer)
@@ -1540,6 +1586,11 @@
self.visit(node.expr, frame)
self.write(')')
+ def visit_MarkSafeIfAutoescape(self, node, frame):
+ self.write('(context.eval_ctx.autoescape and Markup or identity)(')
+ self.visit(node.expr, frame)
+ self.write(')')
+
def visit_EnvironmentAttribute(self, node, frame):
self.write('environment.' + node.name)
@@ -1568,3 +1619,24 @@
self.pull_locals(scope_frame)
self.blockvisit(node.body, scope_frame)
self.pop_scope(aliases, scope_frame)
+
+ def visit_EvalContextModifier(self, node, frame):
+ for keyword in node.options:
+ self.writeline('context.eval_ctx.%s = ' % keyword.key)
+ self.visit(keyword.value, frame)
+ try:
+ val = keyword.value.as_const(frame.eval_ctx)
+ except nodes.Impossible:
+ frame.eval_ctx.volatile = True
+ else:
+ setattr(frame.eval_ctx, keyword.key, val)
+
+ def visit_ScopedEvalContextModifier(self, node, frame):
+ old_ctx_name = self.temporary_identifier()
+ safed_ctx = frame.eval_ctx.save()
+ self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
+ self.visit_EvalContextModifier(node, frame)
+ for child in node.body:
+ self.visit(child, frame)
+ frame.eval_ctx.revert(safed_ctx)
+ self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)
--- a/bundled/jinja2/jinja2/environment.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/environment.py Fri Jun 11 20:32:12 2010 -0400
@@ -8,6 +8,7 @@
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
+import os
import sys
from jinja2 import nodes
from jinja2.defaults import *
@@ -157,9 +158,15 @@
`None` implicitly into an empty string here.
`autoescape`
- If set to true the XML/HTML autoescaping feature is enabled.
- For more details about auto escaping see
- :class:`~jinja2.utils.Markup`.
+ If set to true the XML/HTML autoescaping feature is enabled by
+ default. For more details about auto escaping see
+ :class:`~jinja2.utils.Markup`. As of Jinja 2.4 this can also
+ be a callable that is passed the template name and has to
+ return `True` or `False` depending on autoescape should be
+ enabled by default.
+
+ .. versionchanged:: 2.4
+ `autoescape` can now be a function
`loader`
The template loader for this environment.
@@ -272,6 +279,13 @@
_environment_sanity_check(self)
+ def add_extension(self, extension):
+ """Adds an extension after the environment was created.
+
+ .. versionadded:: 2.5
+ """
+ self.extensions.update(load_extensions(self, [extension]))
+
def extend(self, **attributes):
"""Add the items to the instance of the environment if they do not exist
yet. This is used by :ref:`extensions <writing-extensions>` to register
@@ -327,6 +341,11 @@
lexer = property(get_lexer, doc="The lexer for this environment.")
+ def iter_extensions(self):
+ """Iterates over the extensions by priority."""
+ return iter(sorted(self.extensions.values(),
+ key=lambda x: x.priority))
+
def getitem(self, obj, argument):
"""Get an item or attribute of an object but prefer the item."""
try:
@@ -400,7 +419,7 @@
because there you usually only want the actual source tokenized.
"""
return reduce(lambda s, e: e.preprocess(s, name, filename),
- self.extensions.itervalues(), unicode(source))
+ self.iter_extensions(), unicode(source))
def _tokenize(self, source, name, filename=None, state=None):
"""Called by the parser to do the preprocessing and filtering
@@ -408,14 +427,31 @@
"""
source = self.preprocess(source, name, filename)
stream = self.lexer.tokenize(source, name, filename, state)
- for ext in self.extensions.itervalues():
+ for ext in self.iter_extensions():
stream = ext.filter_stream(stream)
if not isinstance(stream, TokenStream):
stream = TokenStream(stream, name, filename)
return stream
+ def _generate(self, source, name, filename, defer_init=False):
+ """Internal hook that can be overriden to hook a different generate
+ method in.
+
+ .. versionadded:: 2.5
+ """
+ return generate(source, self, name, filename, defer_init=defer_init)
+
+ def _compile(self, source, filename):
+ """Internal hook that can be overriden to hook a different compile
+ method in.
+
+ .. versionadded:: 2.5
+ """
+ return compile(source, filename, 'exec')
+
@internalcode
- def compile(self, source, name=None, filename=None, raw=False):
+ def compile(self, source, name=None, filename=None, raw=False,
+ defer_init=False):
"""Compile a node or template source code. The `name` parameter is
the load name of the template after it was joined using
:meth:`join_path` if necessary, not the filename on the file system.
@@ -427,6 +463,13 @@
parameter is `True` the return value will be a string with python
code equivalent to the bytecode returned otherwise. This method is
mainly used internally.
+
+ `defer_init` is use internally to aid the module code generator. This
+ causes the generated code to be able to import without the global
+ environment variable to be set.
+
+ .. versionadded:: 2.4
+ `defer_init` parameter added.
"""
source_hint = None
try:
@@ -435,14 +478,15 @@
source = self._parse(source, name, filename)
if self.optimized:
source = optimize(source, self)
- source = generate(source, self, name, filename)
+ source = self._generate(source, name, filename,
+ defer_init=defer_init)
if raw:
return source
if filename is None:
filename = '<template>'
else:
filename = _encode_filename(filename)
- return compile(source, filename, 'exec')
+ return self._compile(source, filename)
except TemplateSyntaxError:
exc_info = sys.exc_info()
self.handle_exception(exc_info, source_hint=source)
@@ -483,6 +527,7 @@
raise TemplateSyntaxError('chunk after expression',
parser.stream.current.lineno,
None, None)
+ expr.set_environment(self)
except TemplateSyntaxError:
exc_info = sys.exc_info()
if exc_info is not None:
@@ -491,6 +536,114 @@
template = self.from_string(nodes.Template(body, lineno=1))
return TemplateExpression(template, undefined_to_none)
+ def compile_templates(self, target, extensions=None, filter_func=None,
+ zip='deflated', log_function=None,
+ ignore_errors=True, py_compile=False):
+ """Compiles all the templates the loader can find, compiles them
+ and stores them in `target`. If `zip` is `None`, instead of in a
+ zipfile, the templates will be will be stored in a directory.
+ By default a deflate zip algorithm is used, to switch to
+ the stored algorithm, `zip` can be set to ``'stored'``.
+
+ `extensions` and `filter_func` are passed to :meth:`list_templates`.
+ Each template returned will be compiled to the target folder or
+ zipfile.
+
+ By default template compilation errors are ignored. In case a
+ log function is provided, errors are logged. If you want template
+ syntax errors to abort the compilation you can set `ignore_errors`
+ to `False` and you will get an exception on syntax errors.
+
+ If `py_compile` is set to `True` .pyc files will be written to the
+ target instead of standard .py files.
+
+ .. versionadded:: 2.4
+ """
+ from jinja2.loaders import ModuleLoader
+
+ if log_function is None:
+ log_function = lambda x: None
+
+ if py_compile:
+ import imp, struct, marshal
+ py_header = imp.get_magic() + \
+ u'\xff\xff\xff\xff'.encode('iso-8859-15')
+
+ def write_file(filename, data, mode):
+ if zip:
+ info = ZipInfo(filename)
+ info.external_attr = 0755 << 16L
+ zip_file.writestr(info, data)
+ else:
+ f = open(os.path.join(target, filename), mode)
+ try:
+ f.write(data)
+ finally:
+ f.close()
+
+ if zip is not None:
+ from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED
+ zip_file = ZipFile(target, 'w', dict(deflated=ZIP_DEFLATED,
+ stored=ZIP_STORED)[zip])
+ log_function('Compiling into Zip archive "%s"' % target)
+ else:
+ if not os.path.isdir(target):
+ os.makedirs(target)
+ log_function('Compiling into folder "%s"' % target)
+
+ try:
+ for name in self.list_templates(extensions, filter_func):
+ source, filename, _ = self.loader.get_source(self, name)
+ try:
+ code = self.compile(source, name, filename, True, True)
+ except TemplateSyntaxError, e:
+ if not ignore_errors:
+ raise
+ log_function('Could not compile "%s": %s' % (name, e))
+ continue
+
+ filename = ModuleLoader.get_module_filename(name)
+
+ if py_compile:
+ c = self._compile(code, _encode_filename(filename))
+ write_file(filename + 'c', py_header +
+ marshal.dumps(c), 'wb')
+ log_function('Byte-compiled "%s" as %s' %
+ (name, filename + 'c'))
+ else:
+ write_file(filename, code, 'w')
+ log_function('Compiled "%s" as %s' % (name, filename))
+ finally:
+ if zip:
+ zip_file.close()
+
+ log_function('Finished compiling templates')
+
+ def list_templates(self, extensions=None, filter_func=None):
+ """Returns a list of templates for this environment. This requires
+ that the loader supports the loader's
+ :meth:`~BaseLoader.list_templates` method.
+
+ If there are other files in the template folder besides the
+ actual templates, the returned list can be filtered. There are two
+ ways: either `extensions` is set to a list of file extensions for
+ templates, or a `filter_func` can be provided which is a callable that
+ is passed a template name and should return `True` if it should end up
+ in the result list.
+
+ If the loader does not support that, a :exc:`TypeError` is raised.
+ """
+ x = self.loader.list_templates()
+ if extensions is not None:
+ if filter_func is not None:
+ raise TypeError('either extensions or filter_func '
+ 'can be passed, but not both')
+ filter_func = lambda x: '.' in x and \
+ x.rsplit('.', 1)[1] in extensions
+ if filter_func is not None:
+ x = filter(filter_func, x)
+ return x
+
def handle_exception(self, exc_info=None, rendered=False, source_hint=None):
"""Exception handling helper. This is used internally to either raise
rewritten exceptions or return a rendered traceback for the template.
@@ -679,16 +832,31 @@
"""Creates a template object from compiled code and the globals. This
is used by the loaders and environment to create a template object.
"""
- t = object.__new__(cls)
namespace = {
- 'environment': environment,
- '__jinja_template__': t
+ 'environment': environment,
+ '__file__': code.co_filename
}
exec code in namespace
+ rv = cls._from_namespace(environment, namespace, globals)
+ rv._uptodate = uptodate
+ return rv
+
+ @classmethod
+ def from_module_dict(cls, environment, module_dict, globals):
+ """Creates a template object from a module. This is used by the
+ module loader to create a template object.
+
+ .. versionadded:: 2.4
+ """
+ return cls._from_namespace(environment, module_dict, globals)
+
+ @classmethod
+ def _from_namespace(cls, environment, namespace, globals):
+ t = object.__new__(cls)
t.environment = environment
t.globals = globals
t.name = namespace['name']
- t.filename = code.co_filename
+ t.filename = namespace['__file__']
t.blocks = namespace['blocks']
# render function and module
@@ -697,7 +865,11 @@
# debug and loader helpers
t._debug_info = namespace['debug_info']
- t._uptodate = uptodate
+ t._uptodate = None
+
+ # store the reference
+ namespace['environment'] = environment
+ namespace['__jinja_template__'] = t
return t
--- a/bundled/jinja2/jinja2/ext.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/ext.py Fri Jun 11 20:32:12 2010 -0400
@@ -57,6 +57,13 @@
#: if this extension parses this is the list of tags it's listening to.
tags = set()
+ #: the priority of that extension. This is especially useful for
+ #: extensions that preprocess values. A lower value means higher
+ #: priority.
+ #:
+ #: .. versionadded:: 2.4
+ priority = 100
+
def __init__(self, environment):
self.environment = environment
@@ -116,8 +123,29 @@
@contextfunction
-def _gettext_alias(context, string):
- return context.resolve('gettext')(string)
+def _gettext_alias(__context, *args, **kwargs):
+ return __context.call(__context.resolve('gettext'), *args, **kwargs)
+
+
+def _make_new_gettext(func):
+ @contextfunction
+ def gettext(__context, __string, **variables):
+ rv = __context.call(func, __string)
+ if __context.eval_ctx.autoescape:
+ rv = Markup(rv)
+ return rv % variables
+ return gettext
+
+
+def _make_new_ngettext(func):
+ @contextfunction
+ def ngettext(__context, __singular, __plural, __num, **variables):
+ variables.setdefault('num', __num)
+ rv = __context.call(func, __singular, __plural, __num)
+ if __context.eval_ctx.autoescape:
+ rv = Markup(rv)
+ return rv % variables
+ return ngettext
class InternationalizationExtension(Extension):
@@ -137,23 +165,37 @@
environment.extend(
install_gettext_translations=self._install,
install_null_translations=self._install_null,
+ install_gettext_callables=self._install_callables,
uninstall_gettext_translations=self._uninstall,
- extract_translations=self._extract
+ extract_translations=self._extract,
+ newstyle_gettext=False
)
- def _install(self, translations):
+ def _install(self, translations, newstyle=None):
gettext = getattr(translations, 'ugettext', None)
if gettext is None:
gettext = translations.gettext
ngettext = getattr(translations, 'ungettext', None)
if ngettext is None:
ngettext = translations.ngettext
- self.environment.globals.update(gettext=gettext, ngettext=ngettext)
+ self._install_callables(gettext, ngettext, newstyle)
+
+ def _install_null(self, newstyle=None):
+ self._install_callables(
+ lambda x: x,
+ lambda s, p, n: (n != 1 and (p,) or (s,))[0],
+ newstyle
+ )
- def _install_null(self):
+ def _install_callables(self, gettext, ngettext, newstyle=None):
+ if newstyle is not None:
+ self.environment.newstyle_gettext = newstyle
+ if self.environment.newstyle_gettext:
+ gettext = _make_new_gettext(gettext)
+ ngettext = _make_new_ngettext(ngettext)
self.environment.globals.update(
- gettext=lambda x: x,
- ngettext=lambda s, p, n: (n != 1 and (p,) or (s,))[0]
+ gettext=gettext,
+ ngettext=ngettext
)
def _uninstall(self, translations):
@@ -168,6 +210,7 @@
def parse(self, parser):
"""Parse a translatable tag."""
lineno = next(parser.stream).lineno
+ num_called_num = False
# find all the variables referenced. Additionally a variable can be
# defined in the body of the trans block too, but this is checked at
@@ -194,8 +237,10 @@
variables[name.value] = var = parser.parse_expression()
else:
variables[name.value] = var = nodes.Name(name.value, 'load')
+
if plural_expr is None:
plural_expr = var
+ num_called_num = name.value == 'num'
parser.stream.expect('block_end')
@@ -209,6 +254,7 @@
referenced.update(singular_names)
if plural_expr is None:
plural_expr = nodes.Name(singular_names[0], 'load')
+ num_called_num = singular_names[0] == 'num'
# if we have a pluralize block, we parse that too
if parser.stream.current.test('name:pluralize'):
@@ -221,6 +267,7 @@
name.value, name.lineno,
exc=TemplateAssertionError)
plural_expr = variables[name.value]
+ num_called_num = name.value == 'num'
parser.stream.expect('block_end')
plural_names, plural = self._parse_block(parser, False)
next(parser.stream)
@@ -233,24 +280,13 @@
if var not in variables:
variables[var] = nodes.Name(var, 'load')
- # no variables referenced? no need to escape
- if not referenced:
- singular = singular.replace('%%', '%')
- if plural:
- plural = plural.replace('%%', '%')
-
if not have_plural:
plural_expr = None
elif plural_expr is None:
parser.fail('pluralize without variables', lineno)
- if variables:
- variables = nodes.Dict([nodes.Pair(nodes.Const(x, lineno=lineno), y)
- for x, y in variables.items()])
- else:
- variables = None
-
- node = self._make_node(singular, plural, variables, plural_expr)
+ node = self._make_node(singular, plural, variables, plural_expr,
+ bool(referenced), num_called_num)
node.set_lineno(lineno)
return node
@@ -286,8 +322,16 @@
return referenced, concat(buf)
- def _make_node(self, singular, plural, variables, plural_expr):
+ def _make_node(self, singular, plural, variables, plural_expr,
+ vars_referenced, num_called_num):
"""Generates a useful node from the data provided."""
+ # no variables referenced? no need to escape for old style
+ # gettext invocations
+ if not vars_referenced and not self.environment.newstyle_gettext:
+ singular = singular.replace('%%', '%')
+ if plural:
+ plural = plural.replace('%%', '%')
+
# singular only:
if plural_expr is None:
gettext = nodes.Name('gettext', 'load')
@@ -303,13 +347,27 @@
plural_expr
], [], None, None)
- # mark the return value as safe if we are in an
- # environment with autoescaping turned on
- if self.environment.autoescape:
- node = nodes.MarkSafe(node)
+ # in case newstyle gettext is used, the method is powerful
+ # enough to handle the variable expansion and autoescape
+ # handling itself
+ if self.environment.newstyle_gettext:
+ for key, value in variables.iteritems():
+ # the function adds that later anyways in case num was
+ # called num, so just skip it.
+ if num_called_num and key == 'num':
+ continue
+ node.kwargs.append(nodes.Keyword(key, value))
- if variables:
- node = nodes.Mod(node, variables)
+ # otherwise do that here
+ else:
+ # mark the return value as safe if we are in an
+ # environment with autoescaping turned on
+ node = nodes.MarkSafeIfAutoescape(node)
+ if variables:
+ node = nodes.Mod(node, nodes.Dict([
+ nodes.Pair(nodes.Const(key), value)
+ for key, value in variables.items()
+ ]))
return nodes.Output([node])
@@ -357,6 +415,20 @@
return node
+class AutoEscapeExtension(Extension):
+ """Changes auto escape rules for a scope."""
+ tags = set(['autoescape'])
+
+ def parse(self, parser):
+ node = nodes.ScopedEvalContextModifier(lineno=next(parser.stream).lineno)
+ node.options = [
+ nodes.Keyword('autoescape', parser.parse_expression())
+ ]
+ node.body = parser.parse_statements(('name:endautoescape',),
+ drop_needle=True)
+ return nodes.Scope([node])
+
+
def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS,
babel_style=True):
"""Extract localizable strings from the given template node. Per
@@ -529,3 +601,4 @@
do = ExprStmtExtension
loopcontrols = LoopControlExtension
with_ = WithExtension
+autoescape = AutoEscapeExtension
--- a/bundled/jinja2/jinja2/filters.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/filters.py Fri Jun 11 20:32:12 2010 -0400
@@ -25,18 +25,25 @@
"""Decorator for marking context dependent filters. The current
:class:`Context` will be passed as first argument.
"""
- if getattr(f, 'environmentfilter', False):
- raise TypeError('filter already marked as environment filter')
f.contextfilter = True
return f
+def evalcontextfilter(f):
+ """Decorator for marking eval-context dependent filters. An eval
+ context object is passed as first argument. For more information
+ about the eval context, see :ref:`eval-context`.
+
+ .. versionadded:: 2.4
+ """
+ f.evalcontextfilter = True
+ return f
+
+
def environmentfilter(f):
"""Decorator for marking evironment dependent filters. The current
:class:`Environment` is passed to the filter as first argument.
"""
- if getattr(f, 'contextfilter', False):
- raise TypeError('filter already marked as context filter')
f.environmentfilter = True
return f
@@ -48,8 +55,8 @@
return escape(unicode(value))
-@environmentfilter
-def do_replace(environment, s, old, new, count=None):
+@evalcontextfilter
+def do_replace(eval_ctx, s, old, new, count=None):
"""Return a copy of the value with all occurrences of a substring
replaced with a new one. The first argument is the substring
that should be replaced, the second is the replacement string.
@@ -66,7 +73,7 @@
"""
if count is None:
count = -1
- if not environment.autoescape:
+ if not eval_ctx.autoescape:
return unicode(s).replace(unicode(old), unicode(new), count)
if hasattr(old, '__html__') or hasattr(new, '__html__') and \
not hasattr(s, '__html__'):
@@ -86,8 +93,8 @@
return soft_unicode(s).lower()
-@environmentfilter
-def do_xmlattr(_environment, d, autospace=True):
+@evalcontextfilter
+def do_xmlattr(_eval_ctx, d, autospace=True):
"""Create an SGML/XML attribute string based on the items in a dict.
All values that are neither `none` nor `undefined` are automatically
escaped:
@@ -117,7 +124,7 @@
)
if autospace and rv:
rv = u' ' + rv
- if _environment.autoescape:
+ if _eval_ctx.autoescape:
rv = Markup(rv)
return rv
@@ -169,10 +176,13 @@
return sorted(value.items(), key=sort_func)
-def do_sort(value, case_sensitive=False):
- """Sort an iterable. If the iterable is made of strings the second
- parameter can be used to control the case sensitiveness of the
- comparison which is disabled by default.
+def do_sort(value, reverse=False, case_sensitive=False):
+ """Sort an iterable. Per default it sorts ascending, if you pass it
+ true as first argument it will reverse the sorting.
+
+ If the iterable is made of strings the third parameter can be used to
+ control the case sensitiveness of the comparison which is disabled by
+ default.
.. sourcecode:: jinja
@@ -187,7 +197,7 @@
return item
else:
sort_func = None
- return sorted(seq, key=sort_func)
+ return sorted(value, key=sort_func, reverse=reverse)
def do_default(value, default_value=u'', boolean=False):
@@ -212,8 +222,8 @@
return value
-@environmentfilter
-def do_join(environment, value, d=u''):
+@evalcontextfilter
+def do_join(eval_ctx, value, d=u''):
"""Return a string which is the concatenation of the strings in the
sequence. The separator between elements is an empty string per
default, you can define it with the optional parameter:
@@ -227,7 +237,7 @@
-> 123
"""
# no automatic escaping? joining is a lot eaiser then
- if not environment.autoescape:
+ if not eval_ctx.autoescape:
return unicode(d).join(imap(unicode, value))
# if the delimiter doesn't have an html representation we check
@@ -309,8 +319,8 @@
return pformat(value, verbose=verbose)
-@environmentfilter
-def do_urlize(environment, value, trim_url_limit=None, nofollow=False):
+@evalcontextfilter
+def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False):
"""Converts URLs in plain text into clickable links.
If you pass the filter an additional integer it will shorten the urls
@@ -323,7 +333,7 @@
links are shortened to 40 chars and defined with rel="nofollow"
"""
rv = urlize(value, trim_url_limit, nofollow)
- if environment.autoescape:
+ if eval_ctx.autoescape:
rv = Markup(rv)
return rv
@@ -557,13 +567,6 @@
return func(value)
-def do_sort(value, reverse=False):
- """Sort a sequence. Per default it sorts ascending, if you pass it
- true as first argument it will reverse the sorting.
- """
- return sorted(value, reverse=reverse)
-
-
@environmentfilter
def do_groupby(environment, value, attribute):
"""Group a sequence of objects by a common attribute.
@@ -716,7 +719,6 @@
'sum': sum,
'abs': abs,
'round': do_round,
- 'sort': do_sort,
'groupby': do_groupby,
'safe': do_mark_safe,
'xmlattr': do_xmlattr
--- a/bundled/jinja2/jinja2/lexer.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/lexer.py Fri Jun 11 20:32:12 2010 -0400
@@ -432,9 +432,10 @@
'root': [
# directives
(c('(.*?)(?:%s)' % '|'.join(
- [r'(?P<raw_begin>(?:\s*%s\-|%s)\s*raw\s*%s)' % (
+ [r'(?P<raw_begin>(?:\s*%s\-|%s)\s*raw\s*(?:\-%s\s*|%s))' % (
e(environment.block_start_string),
e(environment.block_start_string),
+ e(environment.block_end_string),
e(environment.block_end_string)
)] + [
r'(?P<%s_begin>\s*%s\-|%s)' % (n, r, r)
--- a/bundled/jinja2/jinja2/loaders.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/loaders.py Fri Jun 11 20:32:12 2010 -0400
@@ -8,6 +8,10 @@
:copyright: (c) 2010 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
+import os
+import sys
+import weakref
+from types import ModuleType
from os import path
try:
from hashlib import sha1
@@ -59,6 +63,12 @@
return source, path, lambda: mtime == getmtime(path)
"""
+ #: if set to `False` it indicates that the loader cannot provide access
+ #: to the source of templates.
+ #:
+ #: .. versionadded:: 2.4
+ has_source_access = True
+
def get_source(self, environment, template):
"""Get the template source, filename and reload helper for a template.
It's passed the environment and template name and has to return a
@@ -77,8 +87,17 @@
old state somewhere (for example in a closure). If it returns `False`
the template will be reloaded.
"""
+ if not self.has_source_access:
+ raise RuntimeError('%s cannot provide access to the source' %
+ self.__class__.__name__)
raise TemplateNotFound(template)
+ def list_templates(self):
+ """Iterates over all templates. If the loader does not support that
+ it should raise a :exc:`TypeError` which is the default behavior.
+ """
+ raise TypeError('this loader cannot iterate over all templates')
+
@internalcode
def load(self, environment, name, globals=None):
"""Loads a template. This method looks up the template in the cache
@@ -160,6 +179,20 @@
return contents, filename, uptodate
raise TemplateNotFound(template)
+ def list_templates(self):
+ found = set()
+ for searchpath in self.searchpath:
+ for dirpath, dirnames, filenames in os.walk(searchpath):
+ for filename in filenames:
+ template = os.path.join(dirpath, filename) \
+ [len(searchpath):].strip(os.path.sep) \
+ .replace(os.path.sep, '/')
+ if template[:2] == './':
+ template = template[2:]
+ if template not in found:
+ found.add(template)
+ return sorted(found)
+
class PackageLoader(BaseLoader):
"""Load templates from python eggs or packages. It is constructed with
@@ -206,6 +239,26 @@
source = self.provider.get_resource_string(self.manager, p)
return source.decode(self.encoding), filename, uptodate
+ def list_templates(self):
+ path = self.package_path
+ if path[:2] == './':
+ path = path[2:]
+ elif path == '.':
+ path = ''
+ offset = len(path)
+ results = []
+ def _walk(path):
+ for filename in self.provider.resource_listdir(path):
+ fullname = path + '/' + filename
+ if self.provider.resource_isdir(fullname):
+ for item in _walk(fullname):
+ results.append(item)
+ else:
+ results.append(fullname[offset:].lstrip('/'))
+ _walk(path)
+ results.sort()
+ return results
+
class DictLoader(BaseLoader):
"""Loads a template from a python dict. It's passed a dict of unicode
@@ -225,6 +278,9 @@
return source, None, lambda: source != self.mapping.get(template)
raise TemplateNotFound(template)
+ def list_templates(self):
+ return sorted(self.mapping)
+
class FunctionLoader(BaseLoader):
"""A loader that is passed a function which does the loading. The
@@ -288,6 +344,13 @@
# (the one that includes the prefix)
raise TemplateNotFound(template)
+ def list_templates(self):
+ result = []
+ for prefix, loader in self.mapping.iteritems():
+ for template in loader.list_templates():
+ result.append(prefix + self.delimiter + template)
+ return result
+
class ChoiceLoader(BaseLoader):
"""This loader works like the `PrefixLoader` just that no prefix is
@@ -313,3 +376,74 @@
except TemplateNotFound:
pass
raise TemplateNotFound(template)
+
+ def list_templates(self):
+ found = set()
+ for loader in self.loaders:
+ found.update(loader.list_templates())
+ return sorted(found)
+
+
+class _TemplateModule(ModuleType):
+ """Like a normal module but with support for weak references"""
+
+
+class ModuleLoader(BaseLoader):
+ """This loader loads templates from precompiled templates.
+
+ Example usage:
+
+ >>> loader = ChoiceLoader([
+ ... ModuleLoader('/path/to/compiled/templates'),
+ ... FileSystemLoader('/path/to/templates')
+ ... ])
+ """
+
+ has_source_access = False
+
+ def __init__(self, path):
+ package_name = '_jinja2_module_templates_%x' % id(self)
+
+ # create a fake module that looks for the templates in the
+ # path given.
+ mod = _TemplateModule(package_name)
+ if isinstance(path, basestring):
+ path = [path]
+ else:
+ path = list(path)
+ mod.__path__ = path
+
+ sys.modules[package_name] = weakref.proxy(mod,
+ lambda x: sys.modules.pop(package_name, None))
+
+ # the only strong reference, the sys.modules entry is weak
+ # so that the garbage collector can remove it once the
+ # loader that created it goes out of business.
+ self.module = mod
+ self.package_name = package_name
+
+ @staticmethod
+ def get_template_key(name):
+ return 'tmpl_' + sha1(name.encode('utf-8')).hexdigest()
+
+ @staticmethod
+ def get_module_filename(name):
+ return ModuleLoader.get_template_key(name) + '.py'
+
+ @internalcode
+ def load(self, environment, name, globals=None):
+ key = self.get_template_key(name)
+ module = '%s.%s' % (self.package_name, key)
+ mod = getattr(self.module, module, None)
+ if mod is None:
+ try:
+ mod = __import__(module, None, None, ['root'])
+ except ImportError:
+ raise TemplateNotFound(name)
+
+ # remove the entry from sys.modules, we only want the attribute
+ # on the module object we have stored on the loader.
+ sys.modules.pop(module, None)
+
+ return environment.template_class.from_module_dict(
+ environment, mod.__dict__, globals)
--- a/bundled/jinja2/jinja2/nodes.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/nodes.py Fri Jun 11 20:32:12 2010 -0400
@@ -15,7 +15,11 @@
import operator
from itertools import chain, izip
from collections import deque
-from jinja2.utils import Markup
+from jinja2.utils import Markup, MethodType, FunctionType
+
+
+#: the types we support for context functions
+_context_function_types = (FunctionType, MethodType)
_binop_to_func = {
@@ -67,6 +71,36 @@
return type.__new__(cls, name, bases, d)
+class EvalContext(object):
+ """Holds evaluation time information. Custom attributes can be attached
+ to it in extensions.
+ """
+
+ def __init__(self, environment, template_name=None):
+ if callable(environment.autoescape):
+ self.autoescape = environment.autoescape(template_name)
+ else:
+ self.autoescape = environment.autoescape
+ self.volatile = False
+
+ def save(self):
+ return self.__dict__.copy()
+
+ def revert(self, old):
+ self.__dict__.clear()
+ self.__dict__.update(old)
+
+
+def get_eval_context(node, ctx):
+ if ctx is None:
+ if node.environment is None:
+ raise RuntimeError('if no eval context is passed, the '
+ 'node must have an attached '
+ 'environment.')
+ return EvalContext(node.environment)
+ return ctx
+
+
class Node(object):
"""Baseclass for all Jinja2 nodes. There are a number of nodes available
of different types. There are three major types:
@@ -312,19 +346,16 @@
"""Baseclass for all expressions."""
abstract = True
- def as_const(self):
+ def as_const(self, eval_ctx=None):
"""Return the value of the expression as constant or raise
- :exc:`Impossible` if this was not possible:
+ :exc:`Impossible` if this was not possible.
- >>> Add(Const(23), Const(42)).as_const()
- 65
- >>> Add(Const(23), Name('var', 'load')).as_const()
- Traceback (most recent call last):
- ...
- Impossible
+ An :class:`EvalContext` can be provided, if none is given
+ a default context is created which requires the nodes to have
+ an attached environment.
- This requires the `environment` attribute of all nodes to be
- set to the environment that created the nodes.
+ .. versionchanged:: 2.4
+ the `eval_ctx` parameter was added.
"""
raise Impossible()
@@ -339,10 +370,11 @@
operator = None
abstract = True
- def as_const(self):
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
f = _binop_to_func[self.operator]
try:
- return f(self.left.as_const(), self.right.as_const())
+ return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))
except:
raise Impossible()
@@ -353,10 +385,11 @@
operator = None
abstract = True
- def as_const(self):
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
f = _uaop_to_func[self.operator]
try:
- return f(self.node.as_const())
+ return f(self.node.as_const(eval_ctx))
except:
raise Impossible()
@@ -389,7 +422,7 @@
"""
fields = ('value',)
- def as_const(self):
+ def as_const(self, eval_ctx=None):
return self.value
@classmethod
@@ -408,8 +441,11 @@
"""A constant template string."""
fields = ('data',)
- def as_const(self):
- if self.environment.autoescape:
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if eval_ctx.volatile:
+ raise Impossible()
+ if eval_ctx.autoescape:
return Markup(self.data)
return self.data
@@ -421,8 +457,9 @@
"""
fields = ('items', 'ctx')
- def as_const(self):
- return tuple(x.as_const() for x in self.items)
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return tuple(x.as_const(eval_ctx) for x in self.items)
def can_assign(self):
for item in self.items:
@@ -435,8 +472,9 @@
"""Any list literal such as ``[1, 2, 3]``"""
fields = ('items',)
- def as_const(self):
- return [x.as_const() for x in self.items]
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return [x.as_const(eval_ctx) for x in self.items]
class Dict(Literal):
@@ -445,24 +483,27 @@
"""
fields = ('items',)
- def as_const(self):
- return dict(x.as_const() for x in self.items)
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return dict(x.as_const(eval_ctx) for x in self.items)
class Pair(Helper):
"""A key, value pair for dicts."""
fields = ('key', 'value')
- def as_const(self):
- return self.key.as_const(), self.value.as_const()
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
class Keyword(Helper):
"""A key, value pair for keyword arguments where key is a string."""
fields = ('key', 'value')
- def as_const(self):
- return self.key, self.value.as_const()
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.key, self.value.as_const(eval_ctx)
class CondExpr(Expr):
@@ -471,15 +512,16 @@
"""
fields = ('test', 'expr1', 'expr2')
- def as_const(self):
- if self.test.as_const():
- return self.expr1.as_const()
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if self.test.as_const(eval_ctx):
+ return self.expr1.as_const(eval_ctx)
# if we evaluate to an undefined object, we better do that at runtime
if self.expr2 is None:
raise Impossible()
- return self.expr2.as_const()
+ return self.expr2.as_const(eval_ctx)
class Filter(Expr):
@@ -491,8 +533,9 @@
"""
fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
- def as_const(self, obj=None):
- if self.node is obj is None:
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if eval_ctx.volatile or self.node is None:
raise Impossible()
# we have to be careful here because we call filter_ below.
# if this variable would be called filter, 2to3 would wrap the
@@ -502,20 +545,21 @@
filter_ = self.environment.filters.get(self.name)
if filter_ is None or getattr(filter_, 'contextfilter', False):
raise Impossible()
- if obj is None:
- obj = self.node.as_const()
- args = [x.as_const() for x in self.args]
- if getattr(filter_, 'environmentfilter', False):
+ obj = self.node.as_const(eval_ctx)
+ args = [x.as_const(eval_ctx) for x in self.args]
+ if getattr(filter_, 'evalcontextfilter', False):
+ args.insert(0, eval_ctx)
+ elif getattr(filter_, 'environmentfilter', False):
args.insert(0, self.environment)
- kwargs = dict(x.as_const() for x in self.kwargs)
+ kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs)
if self.dyn_args is not None:
try:
- args.extend(self.dyn_args.as_const())
+ args.extend(self.dyn_args.as_const(eval_ctx))
except:
raise Impossible()
if self.dyn_kwargs is not None:
try:
- kwargs.update(self.dyn_kwargs.as_const())
+ kwargs.update(self.dyn_kwargs.as_const(eval_ctx))
except:
raise Impossible()
try:
@@ -540,25 +584,31 @@
"""
fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
- def as_const(self):
- obj = self.node.as_const()
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if eval_ctx.volatile:
+ raise Impossible()
+ obj = self.node.as_const(eval_ctx)
# don't evaluate context functions
- args = [x.as_const() for x in self.args]
- if getattr(obj, 'contextfunction', False):
- raise Impossible()
- elif getattr(obj, 'environmentfunction', False):
- args.insert(0, self.environment)
+ args = [x.as_const(eval_ctx) for x in self.args]
+ if isinstance(obj, _context_function_types):
+ if getattr(obj, 'contextfunction', False):
+ raise Impossible()
+ elif getattr(obj, 'evalcontextfunction', False):
+ args.insert(0, eval_ctx)
+ elif getattr(obj, 'environmentfunction', False):
+ args.insert(0, self.environment)
- kwargs = dict(x.as_const() for x in self.kwargs)
+ kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs)
if self.dyn_args is not None:
try:
- args.extend(self.dyn_args.as_const())
+ args.extend(self.dyn_args.as_const(eval_ctx))
except:
raise Impossible()
if self.dyn_kwargs is not None:
try:
- kwargs.update(self.dyn_kwargs.as_const())
+ kwargs.update(self.dyn_kwargs.as_const(eval_ctx))
except:
raise Impossible()
try:
@@ -571,12 +621,13 @@
"""Get an attribute or item from an expression and prefer the item."""
fields = ('node', 'arg', 'ctx')
- def as_const(self):
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
if self.ctx != 'load':
raise Impossible()
try:
- return self.environment.getitem(self.node.as_const(),
- self.arg.as_const())
+ return self.environment.getitem(self.node.as_const(eval_ctx),
+ self.arg.as_const(eval_ctx))
except:
raise Impossible()
@@ -590,11 +641,13 @@
"""
fields = ('node', 'attr', 'ctx')
- def as_const(self):
+ def as_const(self, eval_ctx=None):
if self.ctx != 'load':
raise Impossible()
try:
- return self.environment.getattr(self.node.as_const(), arg)
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.environment.getattr(self.node.as_const(eval_ctx),
+ self.attr)
except:
raise Impossible()
@@ -608,11 +661,12 @@
"""
fields = ('start', 'stop', 'step')
- def as_const(self):
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
def const(obj):
if obj is None:
- return obj
- return obj.as_const()
+ return None
+ return obj.as_const(eval_ctx)
return slice(const(self.start), const(self.stop), const(self.step))
@@ -622,8 +676,9 @@
"""
fields = ('nodes',)
- def as_const(self):
- return ''.join(unicode(x.as_const()) for x in self.nodes)
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return ''.join(unicode(x.as_const(eval_ctx)) for x in self.nodes)
class Compare(Expr):
@@ -632,11 +687,12 @@
"""
fields = ('expr', 'ops')
- def as_const(self):
- result = value = self.expr.as_const()
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ result = value = self.expr.as_const(eval_ctx)
try:
for op in self.ops:
- new_value = op.expr.as_const()
+ new_value = op.expr.as_const(eval_ctx)
result = _cmpop_to_func[op.op](value, new_value)
value = new_value
except:
@@ -695,16 +751,18 @@
"""Short circuited AND."""
operator = 'and'
- def as_const(self):
- return self.left.as_const() and self.right.as_const()
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
class Or(BinExpr):
"""Short circuited OR."""
operator = 'or'
- def as_const(self):
- return self.left.as_const() or self.right.as_const()
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
class Not(UnaryExpr):
@@ -769,12 +827,40 @@
"""Mark the wrapped expression as safe (wrap it as `Markup`)."""
fields = ('expr',)
- def as_const(self):
- return Markup(self.expr.as_const())
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return Markup(self.expr.as_const(eval_ctx))
+
+
+class MarkSafeIfAutoescape(Expr):
+ """Mark the wrapped expression as safe (wrap it as `Markup`) but
+ only if autoescaping is active.
+
+ .. versionadded:: 2.5
+ """
+ fields = ('expr',)
+
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if eval_ctx.volatile:
+ raise Impossible()
+ expr = self.expr.as_const(eval_ctx)
+ if eval_ctx.autoescape:
+ return Markup(expr)
+ return expr
class ContextReference(Expr):
- """Returns the current template context."""
+ """Returns the current template context. It can be used like a
+ :class:`Name` node, with a ``'load'`` ctx and will return the
+ current :class:`~jinja2.runtime.Context` object.
+
+ Here an example that assigns the current template name to a
+ variable named `foo`::
+
+ Assign(Name('foo', ctx='store'),
+ Getattr(ContextReference(), 'name'))
+ """
class Continue(Stmt):
@@ -790,6 +876,25 @@
fields = ('body',)
+class EvalContextModifier(Stmt):
+ """Modifies the eval context. For each option that should be modified,
+ a :class:`Keyword` has to be added to the :attr:`options` list.
+
+ Example to change the `autoescape` setting::
+
+ EvalContextModifier(options=[Keyword('autoescape', Const(True))])
+ """
+ fields = ('options',)
+
+
+class ScopedEvalContextModifier(EvalContextModifier):
+ """Modifies the eval context and reverts it later. Works exactly like
+ :class:`EvalContextModifier` but will only modify the
+ :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
+ """
+ fields = ('body',)
+
+
# make sure nobody creates custom nodes
def _failing_new(*args, **kwargs):
raise TypeError('can\'t create custom node types')
--- a/bundled/jinja2/jinja2/parser.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/parser.py Fri Jun 11 20:32:12 2010 -0400
@@ -34,7 +34,7 @@
self.filename = filename
self.closed = False
self.extensions = {}
- for extension in environment.extensions.itervalues():
+ for extension in environment.iter_extensions():
for tag in extension.tags:
self.extensions[tag] = extension.parse
self._last_identifier = 0
--- a/bundled/jinja2/jinja2/runtime.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/runtime.py Fri Jun 11 20:32:12 2010 -0400
@@ -10,8 +10,9 @@
"""
import sys
from itertools import chain, imap
+from jinja2.nodes import EvalContext, _context_function_types
from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \
- concat, MethodType, FunctionType, internalcode, next
+ concat, internalcode, next, object_type_repr
from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
TemplateNotFound
@@ -19,18 +20,17 @@
# these variables are exported to the template runtime
__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
'TemplateRuntimeError', 'missing', 'concat', 'escape',
- 'markup_join', 'unicode_join', 'to_string',
+ 'markup_join', 'unicode_join', 'to_string', 'identity',
'TemplateNotFound']
-
-#: the types we support for context functions
-_context_function_types = (FunctionType, MethodType)
-
#: the name of the function that is used to convert something into
#: a string. 2to3 will adopt that automatically and the generated
#: code can take advantage of it.
to_string = unicode
+#: the identity function. Useful for certain things in the environment
+identity = lambda x: x
+
def markup_join(seq):
"""Concatenation that escapes if necessary and converts to unicode."""
@@ -76,7 +76,7 @@
def __getitem__(self, name):
blocks = self.__context.blocks[name]
- wrap = self.__context.environment.autoescape and \
+ wrap = self.__context.eval_ctx.autoescape and \
Markup or (lambda x: x)
return BlockReference(name, self.__context, blocks, 0)
@@ -106,13 +106,14 @@
method that doesn't fail with a `KeyError` but returns an
:class:`Undefined` object for missing variables.
"""
- __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
- 'blocks', '__weakref__')
+ __slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars',
+ 'name', 'blocks', '__weakref__')
def __init__(self, environment, parent, name, blocks):
self.parent = parent
self.vars = {}
self.environment = environment
+ self.eval_ctx = EvalContext(self.environment, name)
self.exported_vars = set()
self.name = name
@@ -174,14 +175,22 @@
if isinstance(__obj, _context_function_types):
if getattr(__obj, 'contextfunction', 0):
args = (__self,) + args
+ elif getattr(__obj, 'evalcontextfunction', 0):
+ args = (__self.eval_ctx,) + args
elif getattr(__obj, 'environmentfunction', 0):
args = (__self.environment,) + args
- return __obj(*args, **kwargs)
+ try:
+ return __obj(*args, **kwargs)
+ except StopIteration:
+ return __self.environment.undefined('value was undefined because '
+ 'a callable raised a '
+ 'StopIteration exception')
def derived(self, locals=None):
"""Internal helper function to create a derived context."""
context = new_context(self.environment, self.name, {},
self.parent, True, None, locals)
+ context.eval_ctx = self.eval_ctx
context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems())
return context
@@ -252,7 +261,7 @@
@internalcode
def __call__(self):
rv = concat(self._stack[self._depth](self._context))
- if self._context.environment.autoescape:
+ if self._context.eval_ctx.autoescape:
rv = Markup(rv)
return rv
@@ -341,7 +350,7 @@
class Macro(object):
- """Wraps a macro."""
+ """Wraps a macro function."""
def __init__(self, environment, func, name, arguments, defaults,
catch_kwargs, catch_varargs, caller):
@@ -357,20 +366,24 @@
@internalcode
def __call__(self, *args, **kwargs):
- arguments = []
- for idx, name in enumerate(self.arguments):
- try:
- value = args[idx]
- except:
+ # try to consume the positional arguments
+ arguments = list(args[:self._argument_count])
+ off = len(arguments)
+
+ # if the number of arguments consumed is not the number of
+ # arguments expected we start filling in keyword arguments
+ # and defaults.
+ if off != self._argument_count:
+ for idx, name in enumerate(self.arguments[len(arguments):]):
try:
value = kwargs.pop(name)
- except:
+ except KeyError:
try:
- value = self.defaults[idx - self._argument_count]
- except:
+ value = self.defaults[idx - self._argument_count + off]
+ except IndexError:
value = self._environment.undefined(
'parameter %r was not provided' % name, name=name)
- arguments.append(value)
+ arguments.append(value)
# it's important that the order of these arguments does not change
# if not also changed in the compiler's `function_scoping` method.
@@ -417,7 +430,7 @@
__slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
'_undefined_exception')
- def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
+ def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
self._undefined_hint = hint
self._undefined_obj = obj
self._undefined_name = name
@@ -429,16 +442,16 @@
`UndefinedError` on call.
"""
if self._undefined_hint is None:
- if self._undefined_obj is None:
+ if self._undefined_obj is missing:
hint = '%r is undefined' % self._undefined_name
elif not isinstance(self._undefined_name, basestring):
- hint = '%r object has no element %r' % (
- self._undefined_obj.__class__.__name__,
+ hint = '%s has no element %r' % (
+ object_type_repr(self._undefined_obj),
self._undefined_name
)
else:
- hint = '%r object has no attribute %r' % (
- self._undefined_obj.__class__.__name__,
+ hint = '%r has no attribute %r' % (
+ object_type_repr(self._undefined_obj),
self._undefined_name
)
else:
@@ -493,10 +506,10 @@
def __unicode__(self):
if self._undefined_hint is None:
- if self._undefined_obj is None:
+ if self._undefined_obj is missing:
return u'{{ %s }}' % self._undefined_name
return '{{ no such element: %s[%r] }}' % (
- self._undefined_obj.__class__.__name__,
+ object_type_repr(self._undefined_obj),
self._undefined_name
)
return u'{{ undefined value printed: %s }}' % self._undefined_hint
@@ -523,7 +536,7 @@
"""
__slots__ = ()
__iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \
- __ne__ = Undefined._fail_with_undefined_error
+ __ne__ = __bool__ = Undefined._fail_with_undefined_error
# remove remaining slots attributes, after the metaclass did the magic they
--- a/bundled/jinja2/jinja2/testsuite/__init__.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/__init__.py Fri Jun 11 20:32:12 2010 -0400
@@ -38,6 +38,18 @@
### use only these methods for testing. If you need standard
### unittest method, wrap them!
+ def setup(self):
+ pass
+
+ def teardown(self):
+ pass
+
+ def setUp(self):
+ self.setup()
+
+ def tearDown(self):
+ self.teardown()
+
def assert_equal(self, a, b):
return self.assertEqual(a, b)
--- a/bundled/jinja2/jinja2/testsuite/api.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/api.py Fri Jun 11 20:32:12 2010 -0400
@@ -17,7 +17,7 @@
from jinja2 import Environment, Undefined, DebugUndefined, \
StrictUndefined, UndefinedError, Template, meta, \
- is_undefined, Template
+ is_undefined, Template, DictLoader
from jinja2.utils import Cycler
env = Environment()
@@ -76,6 +76,23 @@
assert env.get_or_select_template([t]) is t
assert env.get_or_select_template(t) is t
+ def test_autoescape_autoselect(self):
+ def select_autoescape(name):
+ if name is None or '.' not in name:
+ return False
+ return name.endswith('.html')
+ env = Environment(autoescape=select_autoescape,
+ loader=DictLoader({
+ 'test.txt': '{{ foo }}',
+ 'test.html': '{{ foo }}'
+ }))
+ t = env.get_template('test.txt')
+ assert t.render(foo='<foo>') == '<foo>'
+ t = env.get_template('test.html')
+ assert t.render(foo='<foo>') == '<foo>'
+ t = env.from_string('{{ foo }}')
+ assert t.render(foo='<foo>') == '<foo>'
+
class MetaTestCase(JinjaTestCase):
@@ -155,29 +172,36 @@
class UndefinedTestCase(JinjaTestCase):
+ def test_stopiteration_is_undefined(self):
+ def test():
+ raise StopIteration()
+ t = Template('A{{ test() }}B')
+ assert t.render(test=test) == 'AB'
+ t = Template('A{{ test().missingattribute }}B')
+ self.assert_raises(UndefinedError, t.render, test=test)
+
def test_default_undefined(self):
env = Environment(undefined=Undefined)
self.assert_equal(env.from_string('{{ missing }}').render(), u'')
self.assert_raises(UndefinedError,
env.from_string('{{ missing.attribute }}').render)
- self.assert_equal(env.from_string('{{ missing|list }}').render, '[]')
- self.assert_equal(env.from_string('{{ missing is not defined }}').render, 'True')
+ self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]')
+ self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42), '')
self.assert_equal(env.from_string('{{ not missing }}').render(), 'True')
- def test_debug_undefined():
+ def test_debug_undefined(self):
env = Environment(undefined=DebugUndefined)
self.assert_equal(env.from_string('{{ missing }}').render(), '{{ missing }}')
self.assert_raises(UndefinedError,
- env.from_string('{{ missing.attribute }}').render())
+ env.from_string('{{ missing.attribute }}').render)
self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]')
- u'[]'
- self.assert_equal(env.from_string('{{ missing is not defined }}').render, 'True')
+ self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42),
- u"{{ no such element: int['missing'] }}")
+ u"{{ no such element: int object['missing'] }}")
self.assert_equal(env.from_string('{{ not missing }}').render(), 'True')
- def test_strict_undefined():
+ def test_strict_undefined(self):
env = Environment(undefined=StrictUndefined)
self.assert_raises(UndefinedError, env.from_string('{{ missing }}').render)
self.assert_raises(UndefinedError, env.from_string('{{ missing.attribute }}').render)
@@ -188,8 +212,23 @@
def test_indexing_gives_undefined(self):
t = Template("{{ var[42].foo }}")
- assert_raises(UndefinedError, t.render, var=0)
+ self.assert_raises(UndefinedError, t.render, var=0)
+ def test_none_gives_proper_error(self):
+ try:
+ Environment().getattr(None, 'split')()
+ except UndefinedError, e:
+ assert e.message == "'None' has no attribute 'split'"
+ else:
+ assert False, 'expected exception'
+
+ def test_object_repr(self):
+ try:
+ Undefined(obj=42, name='upper')()
+ except UndefinedError, e:
+ assert e.message == "'int object' has no attribute 'upper'"
+ else:
+ assert False, 'expected exception'
def suite():
@@ -197,4 +236,5 @@
suite.addTest(unittest.makeSuite(ExtendedAPITestCase))
suite.addTest(unittest.makeSuite(MetaTestCase))
suite.addTest(unittest.makeSuite(StreamingTestCase))
+ suite.addTest(unittest.makeSuite(UndefinedTestCase))
return suite
--- a/bundled/jinja2/jinja2/testsuite/core_tags.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/core_tags.py Fri Jun 11 20:32:12 2010 -0400
@@ -271,6 +271,12 @@
assert tmpl.module.bar.catch_varargs
assert tmpl.module.baz.caller
+ def test_callself(self):
+ tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|'
+ '{{ foo(x - 1) }}{% endif %}{% endmacro %}'
+ '{{ foo(5) }}')
+ assert tmpl.render() == '5|4|3|2|1'
+
def suite():
suite = unittest.TestSuite()
--- a/bundled/jinja2/jinja2/testsuite/ext.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/ext.py Fri Jun 11 20:32:12 2010 -0400
@@ -31,24 +31,39 @@
_gettext_re = re.compile(r'_\((.*?)\)(?s)')
-templates = {
+i18n_templates = {
+ 'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
+ '{% block body %}{% endblock %}',
+ 'child.html': '{% extends "master.html" %}{% block body %}'
+ '{% trans %}watch out{% endtrans %}{% endblock %}',
+ 'plural.html': '{% trans user_count %}One user online{% pluralize %}'
+ '{{ user_count }} users online{% endtrans %}',
+ 'stringformat.html': '{{ _("User: %(num)s")|format(num=user_count) }}'
+}
+
+newstyle_i18n_templates = {
'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
'{% block body %}{% endblock %}',
'child.html': '{% extends "master.html" %}{% block body %}'
'{% trans %}watch out{% endtrans %}{% endblock %}',
'plural.html': '{% trans user_count %}One user online{% pluralize %}'
'{{ user_count }} users online{% endtrans %}',
- 'stringformat.html': '{{ _("User: %d")|format(user_count) }}'
+ 'stringformat.html': '{{ _("User: %(num)s", num=user_count) }}',
+ 'ngettext.html': '{{ ngettext("%(num)s apple", "%(num)s apples", apples) }}',
+ 'ngettext_long.html': '{% trans num=apples %}{{ num }} apple{% pluralize %}'
+ '{{ num }} apples{% endtrans %}'
}
languages = {
'de': {
- 'missing': 'fehlend',
- 'watch out': 'pass auf',
- 'One user online': 'Ein Benutzer online',
- '%(user_count)s users online': '%(user_count)s Benutzer online',
- 'User: %d': 'Benutzer: %d'
+ 'missing': u'fehlend',
+ 'watch out': u'pass auf',
+ 'One user online': u'Ein Benutzer online',
+ '%(user_count)s users online': u'%(user_count)s Benutzer online',
+ 'User: %(num)s': u'Benutzer: %(num)s',
+ '%(num)s apple': u'%(num)s Apfel',
+ '%(num)s apples': u'%(num)s Äpfel'
}
}
@@ -68,7 +83,7 @@
i18n_env = Environment(
- loader=DictLoader(templates),
+ loader=DictLoader(i18n_templates),
extensions=['jinja2.ext.i18n']
)
i18n_env.globals.update({
@@ -77,6 +92,11 @@
'ngettext': ngettext
})
+newstyle_i18n_env = Environment(
+ loader=DictLoader(newstyle_i18n_templates),
+ extensions=['jinja2.ext.i18n']
+)
+newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True)
class TestExtension(Extension):
tags = set(['test'])
@@ -140,6 +160,12 @@
class ExtensionsTestCase(JinjaTestCase):
+ def test_extend_late(self):
+ env = Environment()
+ env.add_extension('jinja2.ext.autoescape')
+ t = env.from_string('{% autoescape true %}{{ "<test>" }}{% endautoescape %}')
+ assert t.render() == '<test>'
+
def test_loop_controls(self):
env = Environment(extensions=['jinja2.ext.loopcontrols'])
@@ -204,6 +230,16 @@
out = tmpl.render()
assert out == 'Foo BAR Baz'
+ def test_extension_ordering(self):
+ class T1(Extension):
+ priority = 1
+ class T2(Extension):
+ priority = 2
+ env = Environment(extensions=[T1, T2])
+ ext = list(env.iter_extensions())
+ assert ext[0].__class__ is T1
+ assert ext[1].__class__ is T2
+
class InternationalizationTestCase(JinjaTestCase):
@@ -256,8 +292,141 @@
]
+class NewstyleInternationalizationTestCase(JinjaTestCase):
+
+ def test_trans(self):
+ tmpl = newstyle_i18n_env.get_template('child.html')
+ assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf'
+
+ def test_trans_plural(self):
+ tmpl = newstyle_i18n_env.get_template('plural.html')
+ assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online'
+ assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online'
+
+ def test_complex_plural(self):
+ tmpl = newstyle_i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% '
+ 'pluralize count %}{{ count }} items{% endtrans %}')
+ assert tmpl.render() == '2 items'
+ self.assert_raises(TemplateAssertionError, i18n_env.from_string,
+ '{% trans foo %}...{% pluralize bar %}...{% endtrans %}')
+
+ def test_trans_stringformatting(self):
+ tmpl = newstyle_i18n_env.get_template('stringformat.html')
+ assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'
+
+ def test_newstyle_plural(self):
+ tmpl = newstyle_i18n_env.get_template('ngettext.html')
+ assert tmpl.render(LANGUAGE='de', apples=1) == '1 Apfel'
+ assert tmpl.render(LANGUAGE='de', apples=5) == u'5 Äpfel'
+
+ def test_autoescape_support(self):
+ env = Environment(extensions=['jinja2.ext.autoescape',
+ 'jinja2.ext.i18n'])
+ env.install_gettext_callables(lambda x: u'<strong>Wert: %(name)s</strong>',
+ lambda s, p, n: s, newstyle=True)
+ t = env.from_string('{% autoescape ae %}{{ gettext("foo", name='
+ '"<test>") }}{% endautoescape %}')
+ assert t.render(ae=True) == '<strong>Wert: <test></strong>'
+ assert t.render(ae=False) == '<strong>Wert: <test></strong>'
+
+ def test_num_used_twice(self):
+ tmpl = newstyle_i18n_env.get_template('ngettext_long.html')
+ assert tmpl.render(apples=5, LANGUAGE='de') == u'5 Äpfel'
+
+ def test_num_called_num(self):
+ source = newstyle_i18n_env.compile('''
+ {% trans num=3 %}{{ num }} apple{% pluralize
+ %}{{ num }} apples{% endtrans %}
+ ''', raw=True)
+ # quite hacky, but the only way to properly test that. The idea is
+ # that the generated code does not pass num twice (although that
+ # would work) for better performance. This only works on the
+ # newstyle gettext of course
+ assert re.search(r"l_ngettext, u?'\%\(num\)s apple', u?'\%\(num\)s "
+ r"apples', 3", source) is not None
+
+
+class AutoEscapeTestCase(JinjaTestCase):
+
+ def test_scoped_setting(self):
+ env = Environment(extensions=['jinja2.ext.autoescape'],
+ autoescape=True)
+ tmpl = env.from_string('''
+ {{ "<HelloWorld>" }}
+ {% autoescape false %}
+ {{ "<HelloWorld>" }}
+ {% endautoescape %}
+ {{ "<HelloWorld>" }}
+ ''')
+ assert tmpl.render().split() == \
+ [u'<HelloWorld>', u'<HelloWorld>', u'<HelloWorld>']
+
+ env = Environment(extensions=['jinja2.ext.autoescape'],
+ autoescape=False)
+ tmpl = env.from_string('''
+ {{ "<HelloWorld>" }}
+ {% autoescape true %}
+ {{ "<HelloWorld>" }}
+ {% endautoescape %}
+ {{ "<HelloWorld>" }}
+ ''')
+ assert tmpl.render().split() == \
+ [u'<HelloWorld>', u'<HelloWorld>', u'<HelloWorld>']
+
+ def test_nonvolatile(self):
+ env = Environment(extensions=['jinja2.ext.autoescape'],
+ autoescape=True)
+ tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
+ assert tmpl.render() == ' foo="<test>"'
+ tmpl = env.from_string('{% autoescape false %}{{ {"foo": "<test>"}'
+ '|xmlattr|escape }}{% endautoescape %}')
+ assert tmpl.render() == ' foo="&lt;test&gt;"'
+
+ def test_volatile(self):
+ env = Environment(extensions=['jinja2.ext.autoescape'],
+ autoescape=True)
+ tmpl = env.from_string('{% autoescape foo %}{{ {"foo": "<test>"}'
+ '|xmlattr|escape }}{% endautoescape %}')
+ assert tmpl.render(foo=False) == ' foo="&lt;test&gt;"'
+ assert tmpl.render(foo=True) == ' foo="<test>"'
+
+ def test_scoping(self):
+ env = Environment(extensions=['jinja2.ext.autoescape'])
+ tmpl = env.from_string('{% autoescape true %}{% set x = "<x>" %}{{ x }}'
+ '{% endautoescape %}{{ x }}{{ "<y>" }}')
+ assert tmpl.render(x=1) == '<x>1<y>'
+
+ def test_volatile_scoping(self):
+ env = Environment(extensions=['jinja2.ext.autoescape'])
+ tmplsource = '''
+ {% autoescape val %}
+ {% macro foo(x) %}
+ [{{ x }}]
+ {% endmacro %}
+ {{ foo().__class__.__name__ }}
+ {% endautoescape %}
+ {{ '<testing>' }}
+ '''
+ tmpl = env.from_string(tmplsource)
+ assert tmpl.render(val=True).split()[0] == 'Markup'
+ assert tmpl.render(val=False).split()[0] == unicode.__name__
+
+ # looking at the source we should see <testing> there in raw
+ # (and then escaped as well)
+ env = Environment(extensions=['jinja2.ext.autoescape'])
+ pysource = env.compile(tmplsource, raw=True)
+ assert '<testing>\\n' in pysource
+
+ env = Environment(extensions=['jinja2.ext.autoescape'],
+ autoescape=True)
+ pysource = env.compile(tmplsource, raw=True)
+ assert '<testing>\\n' in pysource
+
+
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(ExtensionsTestCase))
suite.addTest(unittest.makeSuite(InternationalizationTestCase))
+ suite.addTest(unittest.makeSuite(NewstyleInternationalizationTestCase))
+ suite.addTest(unittest.makeSuite(AutoEscapeTestCase))
return suite
--- a/bundled/jinja2/jinja2/testsuite/filters.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/filters.py Fri Jun 11 20:32:12 2010 -0400
@@ -227,6 +227,10 @@
tmpl = env.from_string('{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}')
assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
+ def test_sort2(self):
+ tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort(false, true)) }}')
+ assert tmpl.render() == 'AbcD'
+
def test_groupby(self):
tmpl = env.from_string('''
{%- for grouper, list in [{'foo': 1, 'bar': 2},
--- a/bundled/jinja2/jinja2/testsuite/lexnparse.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/lexnparse.py Fri Jun 11 20:32:12 2010 -0400
@@ -36,6 +36,10 @@
'{%raw%}{{ bar }}|{% baz %}{% endraw %}')
assert tmpl.render() == 'foo|{{ bar }}|{% baz %}'
+ def test_raw2(self):
+ tmpl = env.from_string('1 {%- raw -%} 2 {%- endraw -%} 3')
+ assert tmpl.render() == '123'
+
def test_balancing(self):
env = Environment('{%', '%}', '${', '}')
tmpl = env.from_string('''{% for item in seq
--- a/bundled/jinja2/jinja2/testsuite/loader.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/loader.py Fri Jun 11 20:32:12 2010 -0400
@@ -9,8 +9,10 @@
:license: BSD, see LICENSE for more details.
"""
import os
+import sys
import time
import tempfile
+import shutil
import unittest
from jinja2.testsuite import JinjaTestCase, dict_loader, \
@@ -98,7 +100,92 @@
self.assert_raises(TemplateNotFound, split_template_path, '../foo')
+class ModuleLoaderTestCase(JinjaTestCase):
+ archive = None
+
+ def compile_down(self, zip='deflated', py_compile=False):
+ super(ModuleLoaderTestCase, self).setup()
+ log = []
+ self.reg_env = Environment(loader=prefix_loader)
+ if zip is not None:
+ self.archive = tempfile.mkstemp(suffix='.zip')[1]
+ else:
+ self.archive = tempfile.mkdtemp()
+ self.reg_env.compile_templates(self.archive, zip=zip,
+ log_function=log.append,
+ py_compile=py_compile)
+ self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
+ return ''.join(log)
+
+ def teardown(self):
+ super(ModuleLoaderTestCase, self).teardown()
+ if hasattr(self, 'mod_env'):
+ if os.path.isfile(self.archive):
+ os.remove(self.archive)
+ else:
+ shutil.rmtree(self.archive)
+ self.archive = None
+
+ def test_log(self):
+ log = self.compile_down()
+ assert 'Compiled "a/foo/test.html" as ' \
+ 'tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a' in log
+ assert 'Finished compiling templates' in log
+ assert 'Could not compile "a/syntaxerror.html": ' \
+ 'Encountered unknown tag \'endif\'' in log
+
+ def _test_common(self):
+ tmpl1 = self.reg_env.get_template('a/test.html')
+ tmpl2 = self.mod_env.get_template('a/test.html')
+ assert tmpl1.render() == tmpl2.render()
+
+ tmpl1 = self.reg_env.get_template('b/justdict.html')
+ tmpl2 = self.mod_env.get_template('b/justdict.html')
+ assert tmpl1.render() == tmpl2.render()
+
+ def test_deflated_zip_compile(self):
+ self.compile_down(zip='deflated')
+ self._test_common()
+
+ def test_stored_zip_compile(self):
+ self.compile_down(zip='stored')
+ self._test_common()
+
+ def test_filesystem_compile(self):
+ self.compile_down(zip=None)
+ self._test_common()
+
+ def test_weak_references(self):
+ self.compile_down()
+ tmpl = self.mod_env.get_template('a/test.html')
+ key = loaders.ModuleLoader.get_template_key('a/test.html')
+ name = self.mod_env.loader.module.__name__
+
+ assert hasattr(self.mod_env.loader.module, key)
+ assert name in sys.modules
+
+ # unset all, ensure the module is gone from sys.modules
+ self.mod_env = tmpl = None
+
+ try:
+ import gc
+ gc.collect()
+ except:
+ pass
+
+ assert name not in sys.modules
+
+ def test_byte_compilation(self):
+ log = self.compile_down(py_compile=True)
+ assert 'Byte-compiled "a/test.html"' in log
+ tmpl1 = self.mod_env.get_template('a/test.html')
+ mod = self.mod_env.loader.module. \
+ tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490
+ assert mod.__file__.endswith('.pyc')
+
+
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(LoaderTestCase))
+ suite.addTest(unittest.makeSuite(ModuleLoaderTestCase))
return suite
--- a/bundled/jinja2/jinja2/testsuite/regression.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/regression.py Fri Jun 11 20:32:12 2010 -0400
@@ -162,6 +162,19 @@
''')
assert t.render(a=0, b=False, c=42, d=42.0) == '1111C'
+ def test_stacked_locals_scoping_bug_twoframe(self):
+ t = Template('''
+ {% set x = 1 %}
+ {% for item in foo %}
+ {% if item == 1 %}
+ {% set x = 2 %}
+ {% endif %}
+ {% endfor %}
+ {{ x }}
+ ''')
+ rv = t.render(foo=[1]).strip()
+ assert rv == u'1'
+
def test_call_with_args(self):
t = Template("""{% macro dump_users(users) -%}
<ul>
--- a/bundled/jinja2/jinja2/testsuite/utils.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/testsuite/utils.py Fri Jun 11 20:32:12 2010 -0400
@@ -18,7 +18,7 @@
from jinja2 import Environment, Undefined, DebugUndefined, \
StrictUndefined, UndefinedError, Template, meta
-from jinja2.utils import LRUCache, escape
+from jinja2.utils import LRUCache, escape, object_type_repr
class LRUCacheTestCase(JinjaTestCase):
@@ -46,6 +46,19 @@
assert copy._queue == cache._queue
+class HelpersTestCase(JinjaTestCase):
+
+ def test_object_type_repr(self):
+ class X(object):
+ pass
+ self.assert_equal(object_type_repr(42), 'int object')
+ self.assert_equal(object_type_repr([]), 'list object')
+ self.assert_equal(object_type_repr(X()),
+ 'jinja2.testsuite.utils.X object')
+ self.assert_equal(object_type_repr(None), 'None')
+ self.assert_equal(object_type_repr(Ellipsis), 'Ellipsis')
+
+
class MarkupLeakTestCase(JinjaTestCase):
def test_markup_leaks(self):
@@ -63,6 +76,7 @@
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(LRUCacheTestCase))
+ suite.addTest(unittest.makeSuite(HelpersTestCase))
# this test only tests the c extension
if not hasattr(escape, 'func_code'):
--- a/bundled/jinja2/jinja2/utils.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/jinja2/utils.py Fri Jun 11 20:32:12 2010 -0400
@@ -127,6 +127,19 @@
return f
+def evalcontextfunction(f):
+ """This decoraotr can be used to mark a function or method as an eval
+ context callable. This is similar to the :func:`contextfunction`
+ but instead of passing the context, an evaluation context object is
+ passed. For more information about the eval context, see
+ :ref:`eval-context`.
+
+ .. versionadded:: 2.4
+ """
+ f.evalcontextfunction = True
+ return f
+
+
def environmentfunction(f):
"""This decorator can be used to mark a function or method as environment
callable. This decorator works exactly like the :func:`contextfunction`
@@ -214,6 +227,23 @@
raise
+def object_type_repr(obj):
+ """Returns the name of the object's type. For some recognized
+ singletons the name of the object is returned instead. (For
+ example for `None` and `Ellipsis`).
+ """
+ if obj is None:
+ return 'None'
+ elif obj is Ellipsis:
+ return 'Ellipsis'
+ # __builtin__ in 2.x, builtins in 3.x
+ if obj.__class__.__module__ in ('__builtin__', 'builtins'):
+ name = obj.__class__.__name__
+ else:
+ name = obj.__class__.__module__ + '.' + obj.__class__.__name__
+ return '%s object' % name
+
+
def pformat(obj, verbose=False):
"""Prettyprint an object. Either use the `pretty` library or the
builtin `pprint`.
--- a/bundled/jinja2/setup.py Fri Jun 11 20:14:01 2010 -0400
+++ b/bundled/jinja2/setup.py Fri Jun 11 20:32:12 2010 -0400
@@ -55,7 +55,7 @@
setup(
name='Jinja2',
- version='2.4',
+ version='2.6',
url='http://jinja.pocoo.org/',
license='BSD',
author='Armin Ronacher',