first version of the jinja2 docs
authorArmin Ronacher <armin.ronacher@active-4.com>
Mon, 28 Apr 2008 11:52:21 +0000 (13:52 +0200)
committerArmin Ronacher <armin.ronacher@active-4.com>
Mon, 28 Apr 2008 11:52:21 +0000 (13:52 +0200)
--HG--
branch : trunk

docs/_build/.ignore [new file with mode: 0644]
docs/_static/.ignore [new file with mode: 0644]
docs/_templates/.ignore [new file with mode: 0644]
docs/api.rst [new file with mode: 0644]
docs/conf.py
docs/intro.rst [new file with mode: 0644]
docs/jinjaext.py [new file with mode: 0644]
docs/templates.rst [new file with mode: 0644]
jinja2/filters.py
jinja2/tests.py

diff --git a/docs/_build/.ignore b/docs/_build/.ignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/docs/_static/.ignore b/docs/_static/.ignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/docs/_templates/.ignore b/docs/_templates/.ignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644 (file)
index 0000000..7dacf36
--- /dev/null
@@ -0,0 +1,191 @@
+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 string by using the constructor of
+:class:`Template` class, an environment is created automatically for you.
+
+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')
+
+
+High Level API
+--------------
+
+.. autoclass:: jinja2.environment.Environment
+    :members: from_string, get_template, join_path
+
+    .. 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.
+
+    .. attribute:: tests
+
+        A dict of test funcitons for this environment.  As long as no
+        template way loaded it's safe to modify this dict.
+
+    .. attribute:: globals
+
+        A dict of global variables.  These variables are always available
+        in a template and (if the optimizer is enabled) may not be
+        override by templates.  As long as no template was loaded it's safe
+        to modify this dict.
+
+
+.. autoclass:: jinja2.Template
+    :members: render, stream, generate, include
+
+
+.. autoclass:: jinja2.environment.TemplateStream
+    :members: disable_buffering, enable_buffering
+
+
+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.runtime.Undefined
+
+.. autoclass:: jinja2.runtime.DebugUndefined
+
+.. autoclass:: jinja2.runtime.StrictUndefined
+
+
+Loaders
+-------
+
+Loaders are responsible for loading templates from a resource such as the
+file system and for keeping the compiled modules in memory.  These work like
+Python's `sys.modules` which keeps the imported templates in memory.  Unlike
+`sys.modules` however this cache is limited in size by default and templates
+are automatically reloaded.  Each loader that extends :class:`BaseLoader`
+supports this caching and accepts two parameters to configure it:
+
+`cache_size`
+    The size of the cache.  Per default this is ``50`` which means that if
+    more than 50 templates are loaded the loader will clean out the least
+    recently used template.  If the cache size is set to ``0`` templates are
+    recompiled all the time, if the cache size is ``-1`` the cache will not
+    be cleaned.
+
+`auto_reload`
+    Some loaders load templates from locations where the template sources
+    may change (ie: file system or database).  If `auto_reload` is set to
+    `True` (default) every time a template is requested the loader checks
+    if the source changed and if yes, it will reload the template.  For
+    higher performance it's possible to disable that.
+
+.. autoclass:: jinja2.loaders.FileSystemLoader
+
+.. autoclass:: jinja2.loaders.PackageLoader
+
+.. autoclass:: jinja2.loaders.DictLoader
+
+.. autoclass:: jinja2.loaders.FunctionLoader
+
+.. autoclass:: jinja2.loaders.PrefixLoader
+
+.. autoclass:: jinja2.loaders.ChoiceLoader
+
+All loaders are subclasses of :class:`BaseLoader`.  If you want to create your
+own loader, subclass :class:`BaseLoader` and override `get_source`.
+
+.. autoclass:: jinja2.loaders.BaseLoader
+    :members: get_source, load
+
+
+Utilities
+---------
+
+These helper functions and classes are useful if you add custom filters or
+functions to a Jinja2 environment.
+
+.. autofunction:: jinja2.filters.environmentfilter
+
+.. autofunction:: jinja2.filters.contextfilter
+
+.. autofunction:: jinja2.utils.environmentfunction
+
+.. autofunction:: jinja2.utils.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.
+
+.. autoclass:: jinja2.utils.Markup
+
+
+Exceptions
+----------
+
+.. autoclass:: jinja2.exceptions.TemplateError
+
+.. autoclass:: jinja2.exceptions.UndefinedError
+
+.. autoclass:: jinja2.exceptions.TemplateNotFound
+
+.. autoclass:: jinja2.exceptions.TemplateSyntaxError
+
+.. autoclass:: jinja2.exceptions.TemplateAssertionError
index 501c094489a65fbea59e7474acb25bb80236ff1a..4c984d263b7ded484866aed396af67765c0ea26c 100644 (file)
@@ -16,14 +16,14 @@ 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.abspath('some/directory'))
+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']
+extensions = ['sphinx.ext.autodoc', 'jinjaext']
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
diff --git a/docs/intro.rst b/docs/intro.rst
new file mode 100644 (file)
index 0000000..981401c
--- /dev/null
@@ -0,0 +1,60 @@
+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 Jinja 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 Jinja 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 the `ctypes`_ module should be installed.
+
+.. _ctypes: http://python.net/crew/theller/ctypes/
+
+
+Basic API Usage
+---------------
+
+This section gives you a brief introduction to the Python API for Jinja templates.
+
+The most basic way to create a template and render it is through
+:class:`Template`.  This however is not the recommended way to work with it,
+but the easiest
+
+>>> from jinja2 import Template
+>>> template = Template('Hello {{ name }}!')
+>>> template.render(name='John Doe')
+u'Hello John Doe!'
+
+By creating an instance of :class:`Template` you get back a new template
+object that provides a method called :meth:`~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.
diff --git a/docs/jinjaext.py b/docs/jinjaext.py
new file mode 100644 (file)
index 0000000..c0dfe44
--- /dev/null
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+"""
+    Jinja Documentation Extensions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Support for automatically documenting filters and tests.
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: BSD.
+"""
+import inspect
+from docutils import nodes
+from docutils.statemachine import ViewList
+from sphinx.ext.autodoc import prepare_docstring
+
+
+def format_filter(name, aliases, func):
+    try:
+        argspec = inspect.getargspec(func)
+    except:
+        try:
+            argspec = inspect.getargspec(func.__init__)
+        except:
+            try:
+                argspec = inspect.getargspec(func.__new__)
+            except:
+                return []
+        del argspec[0][0]
+    if getattr(func, 'environmentfilter', False) or \
+       getattr(func, 'contextfilter', False):
+        del argspec[0][0]
+    signature = inspect.formatargspec(*argspec)
+    result = ['.. function:: %s%s' % (name, signature), '']
+    for line in inspect.getdoc(func).splitlines():
+        result.append('    ' + line)
+    if aliases:
+        result.extend(('', '    :aliases: %s' % ', '.join(
+                      '``%s``' % x for x in sorted(aliases))))
+    return result
+
+
+def jinja_filters(dirname, arguments, options, content, lineno,
+                  content_offset, block_text, state, state_machine):
+    from jinja2.defaults import DEFAULT_FILTERS
+    mapping = {}
+    for name, func in DEFAULT_FILTERS.iteritems():
+        mapping.setdefault(func, []).append(name)
+    filters = []
+    for func, names in 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_filter(name, aliases, func):
+            result.append(item, '<jinjaext>')
+
+    node = nodes.paragraph()
+    state.nested_parse(result, content_offset, node)
+    return node.children
+
+
+def setup(app):
+    app.add_directive('jinjafilters', jinja_filters, 1, (0, 0, 0))
diff --git a/docs/templates.rst b/docs/templates.rst
new file mode 100644 (file)
index 0000000..a3b2325
--- /dev/null
@@ -0,0 +1,315 @@
+Template Designer Documentation
+===============================
+
+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:
+
+.. sourcecode:: html+jinja
+
+    <!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
+---------
+
+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 "subscribe" syntax (``[]``) can be used.  The following lines do
+the same:
+
+.. sourcecode:: jinja
+
+    {{ 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.
+
+
+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 spaces:  ``{{ list|join(', ') }}``.
+
+The `builtin-filters`_ below describes all the builtin filters.
+
+
+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 depening 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:
+
+.. sourcecode:: jinja
+
+    {% if loop.index is divisibleby 3 %}
+    {% if loop.index is divisibleby(3) %}
+
+The `builtin-tests`_ below descibes 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:
+
+.. sourcecode:: jinja
+
+    {# note: disabled template because we no longer user this
+        {% for user in users %}
+            ...
+        {% endfor %}
+    #}
+
+
+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:
+
+.. sourcecode:: html+jinja
+
+    <!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 %}
+            &copy; 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:
+
+.. sourcecode:: html+jinja
+
+    {% 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 awsome 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.
+
+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:
+
+.. sourcecode:: jinja
+
+    {% 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:
+
+.. sourcecode:: jinja
+
+    <title>{% block title %}{% endblock %}</title>
+    <h1>{{ self.title() }}</h1>
+    {% block body %}{% endblock %}
+
+
+Unlike Python Jinja does not support multiple inheritance.  So you can only have
+one extends tag called per rendering.
+
+
+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:
+
+.. sourcecode:: jinja
+
+    {% block sidebar %}
+        <h3>Table Of Contents</h3>
+        ...
+        {{ super() }}
+    {% endblock %}
+
+
+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 relay 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.
+
+
+.. _builtin-filters:
+
+List of Builtin Filters
+-----------------------
+
+.. jinjafilters::
+
+
+.. _builtin-tests:
+
+List of Builtin Tests
+---------------------
+
+bleh
index 15323adaf66995f21b91a4a5e94b5356769e104f..e8cf5aafd9efb411a655d3e80e30b7dc82794058 100644 (file)
@@ -607,6 +607,7 @@ FILTERS = {
     'capitalize':           do_capitalize,
     'title':                do_title,
     'default':              do_default,
+    'd':                    do_default,
     'join':                 do_join,
     'count':                len,
     'dictsort':             do_dictsort,
index 59493ac37a016befe1e90c443c8096aaaa0be6ec..01246ff3ba45ecdf1036ff3606bb6f8b6d8144e9 100644 (file)
@@ -112,6 +112,11 @@ def test_iterable(value):
     return True
 
 
+def test_escaped(value):
+    """Check if the value is escaped."""
+    return hasattr(value, '__html__')
+
+
 TESTS = {
     'odd':              test_odd,
     'even':             test_even,
@@ -126,5 +131,6 @@ TESTS = {
     'sequence':         test_sequence,
     'iterable':         test_iterable,
     'callable':         callable,
-    'sameas':           test_sameas
+    'sameas':           test_sameas,
+    'escaped':          test_escaped
 }