From: Armin Ronacher Date: Mon, 28 Apr 2008 11:52:21 +0000 (+0200) Subject: first version of the jinja2 docs X-Git-Tag: 2.0rc1~126 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=3c8b7ade4a8fed525154db87be6f9bbdceac1f6a;p=jinja2.git first version of the jinja2 docs --HG-- branch : trunk --- diff --git a/docs/_build/.ignore b/docs/_build/.ignore new file mode 100644 index 0000000..e69de29 diff --git a/docs/_static/.ignore b/docs/_static/.ignore new file mode 100644 index 0000000..e69de29 diff --git a/docs/_templates/.ignore b/docs/_templates/.ignore new file mode 100644 index 0000000..e69de29 diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..7dacf36 --- /dev/null +++ b/docs/api.rst @@ -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 diff --git a/docs/conf.py b/docs/conf.py index 501c094..4c984d2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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 index 0000000..981401c --- /dev/null +++ b/docs/intro.rst @@ -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 index 0000000..c0dfe44 --- /dev/null +++ b/docs/jinjaext.py @@ -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, '') + + 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 index 0000000..a3b2325 --- /dev/null +++ b/docs/templates.rst @@ -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 + + + + + My Webpage + + + + +

My Webpage

+ {{ a_variable }} + + + +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 + + + + + + {% block head %} + + {% block title %}{% endblock %} - My Webpage + {% endblock %} + + +
{% block content %}{% endblock %}
+ + + +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() }} + + {% endblock %} + {% block content %} +

Index

+

+ Welcome on my awsome homepage. +

+ {% 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 + + {% block title %}{% endblock %} +

{{ self.title() }}

+ {% 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 %} +

Table Of Contents

+ ... + {{ 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 diff --git a/jinja2/filters.py b/jinja2/filters.py index 15323ad..e8cf5aa 100644 --- a/jinja2/filters.py +++ b/jinja2/filters.py @@ -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, diff --git a/jinja2/tests.py b/jinja2/tests.py index 59493ac..01246ff 100644 --- a/jinja2/tests.py +++ b/jinja2/tests.py @@ -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 }