Return-Path: X-Original-To: apmail-ambari-commits-archive@www.apache.org Delivered-To: apmail-ambari-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 95C33112F6 for ; Thu, 4 Sep 2014 13:06:53 +0000 (UTC) Received: (qmail 23285 invoked by uid 500); 4 Sep 2014 13:06:53 -0000 Delivered-To: apmail-ambari-commits-archive@ambari.apache.org Received: (qmail 23216 invoked by uid 500); 4 Sep 2014 13:06:53 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 22693 invoked by uid 99); 4 Sep 2014 13:06:53 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 04 Sep 2014 13:06:53 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id E9A2FA07886; Thu, 4 Sep 2014 13:06:52 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: aonishuk@apache.org To: commits@ambari.apache.org Date: Thu, 04 Sep 2014 13:07:05 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [14/22] AMBARI-7138. Ambari RPM deals with jinja2 dependency incorrectly (aonishuk) http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/custom_fixers/fix_broken_reraising.py ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/custom_fixers/fix_broken_reraising.py b/ambari-common/src/main/python/ambari_jinja2/custom_fixers/fix_broken_reraising.py new file mode 100644 index 0000000..fd0ea68 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/custom_fixers/fix_broken_reraising.py @@ -0,0 +1,21 @@ +from lib2to3 import fixer_base, pytree +from lib2to3.fixer_util import Name, BlankLine, Name, Attr, ArgList + + +class FixBrokenReraising(fixer_base.BaseFix): + PATTERN = """ + raise_stmt< 'raise' any ',' val=any ',' tb=any > + """ + + # run before the broken 2to3 checker with the same goal + # tries to rewrite it with a rule that does not work out for jinja + run_order = 1 + + def transform(self, node, results): + tb = results['tb'].clone() + tb.prefix = '' + with_tb = Attr(results['val'].clone(), Name('with_traceback')) + \ + [ArgList([tb])] + new = pytree.Node(self.syms.simple_stmt, [Name("raise")] + with_tb) + new.prefix = node.prefix + return new http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/custom_fixers/fix_xrange2.py ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/custom_fixers/fix_xrange2.py b/ambari-common/src/main/python/ambari_jinja2/custom_fixers/fix_xrange2.py new file mode 100644 index 0000000..5d35e50 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/custom_fixers/fix_xrange2.py @@ -0,0 +1,11 @@ +from lib2to3 import fixer_base +from lib2to3.fixer_util import Name, BlankLine + + +# whyever this is necessary.. + +class FixXrange2(fixer_base.BaseFix): + PATTERN = "'xrange'" + + def transform(self, node, results): + node.replace(Name('range', prefix=node.prefix)) http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/Makefile ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/Makefile b/ambari-common/src/main/python/ambari_jinja2/docs/Makefile new file mode 100644 index 0000000..5e24ec1 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/Makefile @@ -0,0 +1,75 @@ +# 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 ' where 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." http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/_static/jinja.js ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/_static/jinja.js b/ambari-common/src/main/python/ambari_jinja2/docs/_static/jinja.js new file mode 100644 index 0000000..1c04218 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/_static/jinja.js @@ -0,0 +1,26 @@ +$(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'); + } + }); + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/_static/print.css ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/_static/print.css b/ambari-common/src/main/python/ambari_jinja2/docs/_static/print.css new file mode 100644 index 0000000..fb633d8 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/_static/print.css @@ -0,0 +1,5 @@ +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; } http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/_static/style.css ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/_static/style.css b/ambari-common/src/main/python/ambari_jinja2/docs/_static/style.css new file mode 100644 index 0000000..a1c4d59 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/_static/style.css @@ -0,0 +1,390 @@ +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 , 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; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/_templates/genindex.html ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/_templates/genindex.html b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/genindex.html new file mode 100644 index 0000000..9add6e9 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/genindex.html @@ -0,0 +1,36 @@ +{% extends "layout.html" %} +{% set title = 'Index' %} +{% block body %} + +

Index

+ + {% for key, dummy in genindexentries -%} + {{ key }} {% if not loop.last %}| {% endif %} + {%- endfor %} +
+ + {% for key, entries in genindexentries %} +

{{ key }}

+ + {%- for column in entries|slice(2) if column %} + + {%- endfor %} +
+ {%- for entryname, (links, subitems) in column %} +
{% if links %}{{ entryname|e }} + {% for link in links[1:] %}, [Link]{% endfor %} + {%- else %}{{ entryname|e }}{% endif %}
+ {%- if subitems %} +
+ {%- for subentryname, subentrylinks in subitems %} +
{{ subentryname|e }} + {%- for link in subentrylinks[1:] %}, [Link]{% endfor -%} +
+ {%- endfor %} +
+ {%- endif -%} + {%- endfor %} +
+ {% endfor %} + +{% endblock %} http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/_templates/layout.html ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/_templates/layout.html b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/layout.html new file mode 100644 index 0000000..f682f90 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/layout.html @@ -0,0 +1,77 @@ + + + + Jinja2 Documentation + + + + + {%- if builder != 'htmlhelp' %} + + + + + + {%- endif %} + {%- if use_opensearch and builder != 'htmlhelp' %} + + {%- endif %} + {%- if hasdoc('about') %} + + {%- endif %} + + + + {%- if hasdoc('copyright') %} + + {%- endif %} + + {%- if parents %} + + {%- endif %} + {%- if next %} + + {%- endif %} + {%- if prev %} + + {%- endif %} + {% block extrahead %}{% endblock %} + + +
+
+

Jinja

+
+
+ {%- if prev %} + « {{ prev.title }} | + {%- endif %} + {{ title }} + {%- if next %} + | {{ next.title }} » + {%- endif %} +
+
+ {%- if display_toc %} +
+

Table Of Contents

+ {{ toc }} +
+ {%- endif %} + {% block body %}{% endblock %} +
+
+ + + http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/_templates/opensearch.xml ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/_templates/opensearch.xml b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/opensearch.xml new file mode 100644 index 0000000..9f2fa42 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/opensearch.xml @@ -0,0 +1,9 @@ + + + {{ project }} + Search {{ docstitle }} + utf-8 + + {{ docstitle }} + http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/_templates/page.html ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/_templates/page.html b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/page.html new file mode 100644 index 0000000..ee6cad3 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/page.html @@ -0,0 +1,4 @@ +{% extends 'layout.html' %} +{% block body %} + {{ body }} +{% endblock %} http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/_templates/search.html ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/_templates/search.html b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/search.html new file mode 100644 index 0000000..0c942b7 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/_templates/search.html @@ -0,0 +1,35 @@ +{% extends "layout.html" %} +{% set title = 'Search' %} +{% block extrahead %} + +{% endblock %} +{% block body %} +

Search

+

+ 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. +

+

+ + +

+ {% if search_performed %} +

Search Results

+ {% if not search_results %} +

Your search did not match any results.

+ {% endif %} + {% endif %} +
+ {% if search_results %} +
    + {% for href, caption, context in search_results %} +
  • {{ caption }} +
    {{ context|e }}
    +
  • + {% endfor %} +
+ {% endif %} +
+{% endblock %} http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/api.rst ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/api.rst b/ambari-common/src/main/python/ambari_jinja2/docs/api.rst new file mode 100644 index 0000000..92da04a --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/api.rst @@ -0,0 +1,787 @@ +API +=== + +.. module:: ambari_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 ambari_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 +`. + +.. 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:`~ambari_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:: ambari_jinja2.environment.TemplateStream() + :members: disable_buffering, enable_buffering, dump + + +Autoescaping +------------ + +.. versionadded:: 2.4 + +As of Jinja 2.4 the preferred way to do autoescaping is to enable the +:ref:`autoescape-extension` and to configure a sensible default for +autoescaping. This makes it possible to enable and disable autoescaping +on a per-template basis (HTML versus text for instance). + +Here a recommended setup that enables autoescaping for templates ending +in ``'.html'``, ``'.htm'`` and ``'.xml'`` and disabling it by default +for all other extensions:: + + def guess_autoescape(template_name): + if template_name is None or '.' not in template_name: + return False + ext = template_name.rsplit('.', 1)[1] + return ext in ('html', 'htm', 'xml') + + env = Environment(autoescape=guess_autoescape, + loader=PackageLoader('mypackage'), + extensions=['ambari_jinja2.ext.autoescape']) + +When implementing a guessing autoescape function, make sure you also +accept `None` as valid template name. This will be passed when generating +templates from strings. + +Inside the templates the behaviour can be temporarily changed by using +the `autoescape` block (see :ref:`autoescape-overrides`). + + +.. _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:: ambari_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:: ambari_jinja2.DebugUndefined() + +.. autoclass:: ambari_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:: ambari_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). + + .. attribute:: eval_ctx + + The current :ref:`eval-context`. + + .. automethod:: ambari_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:: ambari_jinja2.BaseLoader + :members: get_source, load + +Here a list of the builtin loaders Jinja2 provides: + +.. autoclass:: ambari_jinja2.FileSystemLoader + +.. autoclass:: ambari_jinja2.PackageLoader + +.. autoclass:: ambari_jinja2.DictLoader + +.. autoclass:: ambari_jinja2.FunctionLoader + +.. autoclass:: ambari_jinja2.PrefixLoader + +.. autoclass:: ambari_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:: ambari_jinja2.BytecodeCache + :members: load_bytecode, dump_bytecode, clear + +.. autoclass:: ambari_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:: ambari_jinja2.FileSystemBytecodeCache + +.. autoclass:: ambari_jinja2.MemcachedBytecodeCache + + +Utilities +--------- + +These helper functions and classes are useful if you add custom filters or +functions to a Jinja2 environment. + +.. autofunction:: ambari_jinja2.environmentfilter + +.. autofunction:: ambari_jinja2.contextfilter + +.. autofunction:: ambari_jinja2.evalcontextfilter + +.. autofunction:: ambari_jinja2.environmentfunction + +.. autofunction:: ambari_jinja2.contextfunction + +.. autofunction:: ambari_jinja2.evalcontextfunction + +.. 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:: ambari_jinja2.clear_caches + +.. autofunction:: ambari_jinja2.is_undefined + +.. autoclass:: ambari_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:: ambari_jinja2.TemplateError + +.. autoexception:: ambari_jinja2.UndefinedError + +.. autoexception:: ambari_jinja2.TemplateNotFound + +.. autoexception:: ambari_jinja2.TemplatesNotFound + +.. autoexception:: ambari_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:: ambari_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 three decorators +exist: :func:`environmentfilter`, :func:`contextfilter` and +:func:`evalcontextfilter`. + +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 ambari_jinja2 import environmentfilter, Markup, escape + + _paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}') + + @evalcontextfilter + def nl2br(eval_ctx, value): + result = u'\n\n'.join(u'

%s

' % p.replace('\n', '
\n') + for p in _paragraph_re.split(escape(value))) + if eval_ctx.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. + + +.. _eval-context: + +Evaluation Context +------------------ + +The evaluation context (short eval context or eval ctx) is a new object +introducted in Jinja 2.4 that makes it possible to activate and deactivate +compiled features at runtime. + +Currently it is only used to enable and disable the automatic escaping but +can be used for extensions as well. + +In previous Jinja versions filters and functions were marked as +environment callables in order to check for the autoescape status from the +environment. In new versions it's encouraged to check the setting from the +evaluation context instead. + +Previous versions:: + + @environmentfilter + def filter(env, value): + result = do_something(value) + if env.autoescape: + result = Markup(result) + return result + +In new versions you can either use a :func:`contextfilter` and access the +evaluation context from the actual context, or use a +:func:`evalcontextfilter` which directly passes the evaluation context to +the function:: + + @contextfilter + def filter(context, value): + result = do_something(value) + if context.eval_ctx.autoescape: + result = Markup(result) + return result + + @evalcontextfilter + def filter(eval_ctx, value): + result = do_something(value) + if eval_ctx.autoescape: + result = Markup(result) + return result + +The evaluation context must not be modified at runtime. Modifications +must only happen with a :class:`nodes.EvalContextModifier` and +:class:`nodes.ScopedEvalContextModifier` from an extension, not on the +eval context object itself. + +.. autoclass:: ambari_jinja2.nodes.EvalContext + + .. attribute:: autoescape + + `True` or `False` depending on if autoescaping is active or not. + + .. attribute:: volatile + + `True` if the compiler cannot evaluate some expressions at compile + time. At runtime this should always be `False`. + + +.. _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 +` 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:: ambari_jinja2.meta.find_undeclared_variables + +.. autofunction:: ambari_jinja2.meta.find_referenced_templates http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/cache_extension.py ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/cache_extension.py b/ambari-common/src/main/python/ambari_jinja2/docs/cache_extension.py new file mode 100644 index 0000000..d3703e3 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/cache_extension.py @@ -0,0 +1,56 @@ +from ambari_jinja2 import nodes +from ambari_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 http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/changelog.rst ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/changelog.rst b/ambari-common/src/main/python/ambari_jinja2/docs/changelog.rst new file mode 100644 index 0000000..6d6d6ca --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/changelog.rst @@ -0,0 +1,3 @@ +.. module:: ambari_jinja2 + +.. include:: ../CHANGES http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/conf.py ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/conf.py b/ambari-common/src/main/python/ambari_jinja2/docs/conf.py new file mode 100644 index 0000000..ba90c49 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/conf.py @@ -0,0 +1,141 @@ +# -*- 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 +# " v 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/. +#html_copy_source = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a 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 http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/extensions.rst ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/extensions.rst b/ambari-common/src/main/python/ambari_jinja2/docs/extensions.rst new file mode 100644 index 0000000..4d2c458 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/extensions.rst @@ -0,0 +1,347 @@ +.. _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=['ambari_jinja2.ext.i18n']) + + +.. _i18n-extension: + +i18n Extension +-------------- + +**Import name:** `ambari_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. + +Environment Methods +~~~~~~~~~~~~~~~~~~~ + +After enabling of the extension the environment provides the following +additional methods: + +.. method:: ambari_jinja2.Environment.install_gettext_translations(translations, newstyle=False) + + 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. + + .. versionchanged:: 2.5 newstyle gettext added + +.. method:: ambari_jinja2.Environment.install_null_translations(newstyle=False) + + 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. + + .. versionchanged:: 2.5 newstyle gettext added + +.. method:: ambari_jinja2.Environment.install_gettext_callables(gettext, ngettext, newstyle=False) + + Installs the given `gettext` and `ngettext` callables into the + environment as globals. They are supposed to behave exactly like the + standard library's :func:`gettext.ugettext` and + :func:`gettext.ungettext` functions. + + If `newstyle` is activated, the callables are wrapped to work like + newstyle callables. See :ref:`newstyle-gettext` for more information. + + .. versionadded:: 2.5 + +.. method:: ambari_jinja2.Environment.uninstall_gettext_translations() + + Uninstall the translations again. + +.. method:: ambari_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 ` + 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=['ambari_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 `. + +.. _gettext: http://docs.python.org/dev/library/gettext +.. _Babel: http://babel.edgewall.org/ + +.. _newstyle-gettext: + +Newstyle Gettext +~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.5 + +Starting with version 2.5 you can use newstyle gettext calls. These are +inspired by trac's internal gettext functions and are fully supported by +the babel extraction tool. They might not work as expected by other +extraction tools in case you are not using Babel's. + +What's the big difference between standard and newstyle gettext calls? In +general they are less to type and less error prone. Also if they are used +in an autoescaping environment they better support automatic escaping. +Here some common differences between old and new calls: + +standard gettext: + +.. sourcecode:: html+jinja + + {{ gettext('Hello World!') }} + {{ gettext('Hello %(name)s!')|format(name='World') }} + {{ ngettext('%(num)d apple', '%(num)d apples', apples|count)|format( + num=apples|count + )}} + +newstyle gettext looks like this instead: + +.. sourcecode:: html+jinja + + {{ gettext('Hello World!') }} + {{ gettext('Hello %(name)s!', name='World') }} + {{ ngettext('%(num)d apple', '%(num)d apples', apples|count) }} + +The advantages of newstyle gettext is that you have less to type and that +named placeholders become mandatory. The latter sounds like a +disadvantage but solves a lot of troubles translators are often facing +when they are unable to switch the positions of two placeholder. With +newstyle gettext, all format strings look the same. + +Furthermore with newstyle gettext, string formatting is also used if no +placeholders are used which makes all strings behave exactly the same. +Last but not least are newstyle gettext calls able to properly mark +strings for autoescaping which solves lots of escaping related issues many +templates are experiencing over time when using autoescaping. + +Expression Statement +-------------------- + +**Import name:** `ambari_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:** `ambari_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:** `ambari_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. + +.. _autoescape-extension: + +Autoescape Extension +-------------------- + +**Import name:** `ambari_jinja2.ext.autoescape` + +.. versionadded:: 2.4 + +The autoescape extension allows you to toggle the autoescape feature from +within the template. If the environment's :attr:`~Environment.autoescape` +setting is set to `False` it can be activated, if it's `True` it can be +deactivated. The setting overriding is scoped. + + +.. _writing-extensions: + +Writing Extensions +------------------ + +.. module:: ambari_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 ambari_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 %} + + {% endcache %} + +.. _Werkzeug: http://werkzeug.pocoo.org/ + +Extension API +~~~~~~~~~~~~~ + +Extensions always have to extend the :class:`ambari_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:: ambari_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:`~ambari_jinja2.lexer.TokenStream` + +.. autoclass:: ambari_jinja2.lexer.TokenStream + :members: push, look, eos, skip, next, next_if, skip_if, expect + + .. attribute:: current + + The current :class:`~ambari_jinja2.lexer.Token`. + +.. autoclass:: ambari_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:: ambari_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:`ambari_jinja2.Environment.parse`. + +.. module:: ambari_jinja2.nodes + +.. jinjanodes:: + +.. autoexception:: Impossible http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/faq.rst ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/faq.rst b/ambari-common/src/main/python/ambari_jinja2/docs/faq.rst new file mode 100644 index 0000000..89186b1 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/faq.rst @@ -0,0 +1,191 @@ +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() %} + +What is the speedups module and why is it missing? +-------------------------------------------------- + +To achieve a good performance with automatic escaping enabled, the escaping +function was also implemented in pure C in older Jinja2 releases and used if +Jinja2 was installed with the speedups module. + +Because this feature itself is very useful for non-template engines as +well it was moved into a separate project on PyPI called `MarkupSafe`_. + +Jinja2 no longer ships with a C implementation of it but only the pure +Python implementation. It will however check if MarkupSafe is available +and installed, and if it is, use the Markup class from MarkupSafe. + +So if you want the speedups, just import MarkupSafe. + +.. _MarkupSafe: http://pypi.python.org/pypi/MarkupSafe + +My tracebacks look weird. What's happening? +-------------------------------------------- + +If the debugsupport 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 debugsupport 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/ http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/index.rst ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/index.rst b/ambari-common/src/main/python/ambari_jinja2/docs/index.rst new file mode 100644 index 0000000..27bee23 --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/index.rst @@ -0,0 +1,27 @@ +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` http://git-wip-us.apache.org/repos/asf/ambari/blob/658360a5/ambari-common/src/main/python/ambari_jinja2/docs/integration.rst ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/ambari_jinja2/docs/integration.rst b/ambari-common/src/main/python/ambari_jinja2/docs/integration.rst new file mode 100644 index 0000000..4f8614a --- /dev/null +++ b/ambari-common/src/main/python/ambari_jinja2/docs/integration.rst @@ -0,0 +1,88 @@ +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 `ambari_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 + + [ambari_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 + + [ambari_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 ambari_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 `_ +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/