diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 16:06:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 16:06:13 +0000 |
commit | ce859b2defe1fc90c7a16551291799fc37284add (patch) | |
tree | 7e6b04791662f8f268c7abc9c07d41e98a261a84 /docs | |
parent | Initial commit. (diff) | |
download | jinja2-da9d4f121fb9f82655563456df2003bcc6d25d08.tar.xz jinja2-da9d4f121fb9f82655563456df2003bcc6d25d08.zip |
Adding upstream version 3.1.2.upstream/3.1.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'docs')
-rw-r--r-- | docs/Makefile | 19 | ||||
-rw-r--r-- | docs/_static/jinja-logo-sidebar.png | bin | 0 -> 10484 bytes | |||
-rw-r--r-- | docs/_static/jinja-logo.png | bin | 0 -> 12854 bytes | |||
-rw-r--r-- | docs/api.rst | 922 | ||||
-rw-r--r-- | docs/changes.rst | 4 | ||||
-rw-r--r-- | docs/conf.py | 53 | ||||
-rw-r--r-- | docs/examples/cache_extension.py | 54 | ||||
-rw-r--r-- | docs/examples/inline_gettext_extension.py | 72 | ||||
-rw-r--r-- | docs/extensions.rst | 423 | ||||
-rw-r--r-- | docs/faq.rst | 75 | ||||
-rw-r--r-- | docs/index.rst | 29 | ||||
-rw-r--r-- | docs/integration.rst | 94 | ||||
-rw-r--r-- | docs/intro.rst | 63 | ||||
-rw-r--r-- | docs/license.rst | 4 | ||||
-rw-r--r-- | docs/make.bat | 35 | ||||
-rw-r--r-- | docs/nativetypes.rst | 64 | ||||
-rw-r--r-- | docs/sandbox.rst | 111 | ||||
-rw-r--r-- | docs/switching.rst | 181 | ||||
-rw-r--r-- | docs/templates.rst | 1949 | ||||
-rw-r--r-- | docs/tricks.rst | 100 |
20 files changed, 4252 insertions, 0 deletions
diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..5128596 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/jinja-logo-sidebar.png b/docs/_static/jinja-logo-sidebar.png Binary files differnew file mode 100644 index 0000000..455b4c3 --- /dev/null +++ b/docs/_static/jinja-logo-sidebar.png diff --git a/docs/_static/jinja-logo.png b/docs/_static/jinja-logo.png Binary files differnew file mode 100644 index 0000000..7f8ca5b --- /dev/null +++ b/docs/_static/jinja-logo.png diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..b2db537 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,922 @@ +API +=== + +.. module:: jinja2 + :noindex: + :synopsis: public Jinja API + +This document describes the API to Jinja and not the template language +(for that, see :doc:`/templates`). It will be most useful as reference +to those implementing the template interface to the application and not +those who are creating Jinja templates. + +Basics +------ + +Jinja uses a central object called the template :class:`Environment`. +Instances of this class are used to store the configuration and 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 however, it's +useful to have multiple environments side by side, if different configurations +are in use. + +The simplest way to configure Jinja to load templates for your +application is to use :class:`~loaders.PackageLoader`. + +.. code-block:: python + + from jinja2 import Environment, PackageLoader, select_autoescape + env = Environment( + loader=PackageLoader("yourapp"), + autoescape=select_autoescape() + ) + +This will create a template environment with a loader that looks up +templates in the ``templates`` folder inside the ``yourapp`` Python +package (or next to the ``yourapp.py`` Python module). It also enables +autoescaping for HTML files. This loader only requires that ``yourapp`` +is importable, it figures out the absolute path to the folder for you. + +Different loaders are available to load templates in other ways or from +other locations. They're listed in the `Loaders`_ section below. You can +also write your own if you want to load templates from a source that's +more specialized to your project. + +To load a template from this environment, call the :meth:`get_template` +method, which returns the loaded :class:`Template`. + +.. code-block:: python + + template = env.get_template("mytemplate.html") + +To render it with some variables, call the :meth:`render` method. + +.. code-block:: python + + print(template.render(the="variables", go="here")) + +Using a template loader rather than 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. + +.. admonition:: Notes on Autoescaping + + In future versions of Jinja we might enable autoescaping by default + for security reasons. As such you are encouraged to explicitly + configure autoescaping now instead of relying on the default. + + +High Level API +-------------- + +The high-level API is the API you will use in the application to load and +render Jinja templates. The :ref:`low-level-api` on the other side is only +useful if you want to dig deeper into Jinja or :ref:`develop extensions +<jinja-extensions>`. + +.. autoclass:: Environment([options]) + :members: from_string, get_template, select_template, + get_or_select_template, join_path, extend, compile_expression, + compile_templates, list_templates, add_extension + + .. attribute:: shared + + If a template was created by using the :class:`Template` constructor + an environment is created automatically. These environments are + created as shared environments which means that multiple templates + may have the same anonymous environment. For all shared environments + this attribute is `True`, else `False`. + + .. attribute:: sandboxed + + If the environment is sandboxed this attribute is `True`. For the + sandbox mode have a look at the documentation for the + :class:`~jinja2.sandbox.SandboxedEnvironment`. + + .. attribute:: filters + + A dict of filters for this environment. As long as no template was + loaded it's safe to add new filters or remove old. For custom filters + see :ref:`writing-filters`. For valid filter names have a look at + :ref:`identifier-naming`. + + .. attribute:: tests + + A dict of test functions for this environment. As long as no + template was loaded it's safe to modify this dict. For custom tests + see :ref:`writing-tests`. For valid test names have a look at + :ref:`identifier-naming`. + + .. attribute:: globals + + A dict of variables that are available in every template loaded + by the environment. As long as no template was loaded it's safe + to modify this. For more details see :ref:`global-namespace`. + For valid object names see :ref:`identifier-naming`. + + .. attribute:: policies + + A dictionary with :ref:`policies`. These can be reconfigured to + change the runtime behavior or certain template features. Usually + these are security related. + + .. attribute:: code_generator_class + + The class used for code generation. This should not be changed + in most cases, unless you need to modify the Python code a + template compiles to. + + .. attribute:: context_class + + The context used for templates. This should not be changed + in most cases, unless you need to modify internals of how + template variables are handled. For details, see + :class:`~jinja2.runtime.Context`. + + .. 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 omitted. + + 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 should 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 + + A dict of variables that are available every time the template + is rendered, without needing to pass them during render. This + should not be modified, as depending on how the template was + loaded it may be shared with the environment and other + templates. + + Defaults to :attr:`Environment.globals` unless extra values are + passed to :meth:`Environment.get_template`. + + Globals are only intended for data that is common to every + render of the template. Specific data should be passed to + :meth:`render`. + + See :ref:`global-namespace`. + + .. 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]) + + .. automethod:: render_async([context]) + + .. automethod:: generate_async([context]) + + +.. autoclass:: jinja2.environment.TemplateStream() + :members: disable_buffering, enable_buffering, dump + + +Autoescaping +------------ + +.. versionchanged:: 2.4 + +Jinja now comes with autoescaping support. As of Jinja 2.9 the +autoescape extension is removed and built-in. However autoescaping is +not yet enabled by default though this will most likely change in the +future. It's recommended 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). + +.. autofunction:: jinja2.select_autoescape + +Here a recommended setup that enables autoescaping for templates ending +in ``'.html'``, ``'.htm'`` and ``'.xml'`` and disabling it by default +for all other extensions. You can use the :func:`~jinja2.select_autoescape` +function for this:: + + from jinja2 import Environment, PackageLoader, select_autoescape + env = Environment(autoescape=select_autoescape(['html', 'htm', 'xml']), + loader=PackageLoader('mypackage')) + +The :func:`~jinja.select_autoescape` function returns a function that +works roughly like this:: + + def autoescape(template_name): + if template_name is None: + return False + if template_name.endswith(('.html', '.htm', '.xml')) + +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. You should always configure autoescaping as +defaults in the future might change. + +Inside the templates the behaviour can be temporarily changed by using +the `autoescape` block (see :ref:`autoescape-overrides`). + + +.. _identifier-naming: + +Notes on Identifiers +-------------------- + +Jinja uses Python naming rules. Valid identifiers can be any combination +of characters accepted by Python. + +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.str`. 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 :class:`StrictUndefined` which +disallows all operations beside testing if it's an undefined object. + +.. autoclass:: jinja2.Undefined() + + .. attribute:: _undefined_hint + + Either `None` or a string with the error message for the + undefined object. + + .. attribute:: _undefined_obj + + Either `None` or the owner object that caused the undefined object + to be created (for example because an attribute does not exist). + + .. attribute:: _undefined_name + + The name for the undefined variable / attribute or just `None` + if no such information exists. + + .. attribute:: _undefined_exception + + The exception that the undefined object wants to raise. This + is usually one of :exc:`UndefinedError` or :exc:`SecurityError`. + + .. method:: _fail_with_undefined_error(\*args, \**kwargs) + + When called with any arguments this method raises + :attr:`_undefined_exception` with an error message generated + from the undefined hints stored on the undefined object. + +.. autoclass:: jinja2.ChainableUndefined() + +.. autoclass:: jinja2.DebugUndefined() + +.. autoclass:: jinja2.StrictUndefined() + +There is also a factory function that can decorate undefined objects to +implement logging on failures: + +.. autofunction:: jinja2.make_logging_undefined + +Undefined objects are created by calling :attr:`undefined`. + +.. admonition:: Implementation + + :class:`Undefined` is implemented by overriding the special + ``__underscore__`` methods. For example the default + :class:`Undefined` class implements ``__str__`` to returns an empty + string, while ``__int__`` and others fail with an exception. To + allow conversion to int by returning ``0`` you can implement your + own subclass. + + .. code-block:: python + + class NullUndefined(Undefined): + def __int__(self): + return 0 + + def __float__(self): + return 0.0 + + To disallow a method, override it and raise + :attr:`~Undefined._undefined_exception`. Because this is very + common there is the helper method + :meth:`~Undefined._fail_with_undefined_error` that raises the error + with the correct information. Here's a class that works like the + regular :class:`Undefined` but fails on iteration:: + + class NonIterableUndefined(Undefined): + def __iter__(self): + self._fail_with_undefined_error() + + +The Context +----------- + +.. autoclass:: jinja2.runtime.Context() + :members: get, resolve, resolve_or_missing, 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:: jinja2.runtime.Context.call(callable, \*args, \**kwargs) + + +The context is immutable, it prevents modifications, and if it is +modified somehow despite that those changes may not show up. For +performance, Jinja does not use the context as data storage for, only as +a primary data source. Variables that the template does not define are +looked up in the context, but variables the template does define are +stored locally. + +Instead of modifying the context directly, a function should return +a value that can be assigned to a variable within the template itself. + +.. code-block:: jinja + + {% set comments = get_latest_comments() %} + + +.. _loaders: + +Loaders +------- + +Loaders are responsible for loading templates from a resource such as the +file system. The environment will keep the compiled modules in memory like +Python's `sys.modules`. Unlike `sys.modules` however this cache is limited in +size by default and templates are automatically reloaded. +All loaders are subclasses of :class:`BaseLoader`. If you want to create your +own loader, subclass :class:`BaseLoader` and override `get_source`. + +.. autoclass:: jinja2.BaseLoader + :members: get_source, load + +Here a list of the builtin loaders Jinja provides: + +.. autoclass:: jinja2.FileSystemLoader + +.. autoclass:: jinja2.PackageLoader + +.. autoclass:: jinja2.DictLoader + +.. autoclass:: jinja2.FunctionLoader + +.. autoclass:: jinja2.PrefixLoader + +.. autoclass:: jinja2.ChoiceLoader + +.. autoclass:: jinja2.ModuleLoader + + +.. _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, instantiate it and pass it to the :class:`Environment`. + +.. autoclass:: jinja2.BytecodeCache + :members: load_bytecode, dump_bytecode, clear + +.. autoclass:: jinja2.bccache.Bucket + :members: write_bytecode, load_bytecode, bytecode_from_string, + bytecode_to_string, reset + + .. attribute:: environment + + The :class:`Environment` that created the bucket. + + .. attribute:: key + + The unique cache key for this bucket + + .. attribute:: code + + The bytecode if it's loaded, otherwise `None`. + + +Builtin bytecode caches: + +.. autoclass:: jinja2.FileSystemBytecodeCache + +.. autoclass:: jinja2.MemcachedBytecodeCache + + +Async Support +------------- + +.. versionadded:: 2.9 + +Jinja supports the Python ``async`` and ``await`` syntax. For the +template designer, this support (when enabled) is entirely transparent, +templates continue to look exactly the same. However, developers should +be aware of the implementation as it affects what types of APIs you can +use. + +By default, async support is disabled. Enabling it will cause the +environment to compile different code behind the scenes in order to +handle async and sync code in an asyncio event loop. This has the +following implications: + +- Template rendering requires an event loop to be available to the + current thread. :func:`asyncio.get_running_loop` must return an + event loop. +- The compiled code uses ``await`` for functions and attributes, and + uses ``async for`` loops. In order to support using both async and + sync functions in this context, a small wrapper is placed around + all calls and access, which adds overhead compared to purely async + code. +- Sync methods and filters become wrappers around their corresponding + async implementations where needed. For example, ``render`` invokes + ``async_render``, and ``|map`` supports async iterables. + +Awaitable objects can be returned from functions in templates and any +function call in a template will automatically await the result. The +``await`` you would normally add in Python is implied. For example, you +can provide a method that asynchronously loads data from a database, and +from the template designer's point of view it can be called like any +other function. + + +.. _policies: + +Policies +-------- + +Starting with Jinja 2.9 policies can be configured on the environment +which can slightly influence how filters and other template constructs +behave. They can be configured with the +:attr:`~jinja2.Environment.policies` attribute. + +Example:: + + env.policies['urlize.rel'] = 'nofollow noopener' + +``truncate.leeway``: + Configures the leeway default for the `truncate` filter. Leeway as + introduced in 2.9 but to restore compatibility with older templates + it can be configured to `0` to get the old behavior back. The default + is `5`. + +``urlize.rel``: + A string that defines the items for the `rel` attribute of generated + links with the `urlize` filter. These items are always added. The + default is `noopener`. + +``urlize.target``: + The default target that is issued for links from the `urlize` filter + if no other target is defined by the call explicitly. + +``urlize.extra_schemes``: + Recognize URLs that start with these schemes in addition to the + default ``http://``, ``https://``, and ``mailto:``. + +``json.dumps_function``: + If this is set to a value other than `None` then the `tojson` filter + will dump with this function instead of the default one. Note that + this function should accept arbitrary extra arguments which might be + passed in the future from the filter. Currently the only argument + that might be passed is `indent`. The default dump function is + ``json.dumps``. + +``json.dumps_kwargs``: + Keyword arguments to be passed to the dump function. The default is + ``{'sort_keys': True}``. + +.. _ext-i18n-trimmed: + +``ext.i18n.trimmed``: + If this is set to `True`, ``{% trans %}`` blocks of the + :ref:`i18n-extension` will always unify linebreaks and surrounding + whitespace as if the `trimmed` modifier was used. + + +Utilities +--------- + +These helper functions and classes are useful if you add custom filters or +functions to a Jinja environment. + +.. autofunction:: jinja2.pass_context + +.. autofunction:: jinja2.pass_eval_context + +.. autofunction:: jinja2.pass_environment + +.. autofunction:: jinja2.clear_caches + +.. autofunction:: jinja2.is_undefined + + +Exceptions +---------- + +.. autoexception:: jinja2.TemplateError + +.. autoexception:: jinja2.UndefinedError + +.. autoexception:: jinja2.TemplateNotFound + +.. autoexception:: jinja2.TemplatesNotFound + +.. autoexception:: jinja2.TemplateSyntaxError + + .. attribute:: message + + The error message. + + .. attribute:: lineno + + The line number where the error occurred. + + .. attribute:: name + + The load name for the template. + + .. attribute:: filename + + The filename that loaded the template in the encoding of the + file system (most likely utf-8, or mbcs on Windows systems). + +.. autoexception:: jinja2.TemplateRuntimeError + +.. autoexception:: jinja2.TemplateAssertionError + + +.. _writing-filters: + +Custom Filters +-------------- + +Filters are Python functions that take the value to the left of the +filter as the first argument and produce a new value. Arguments passed +to the filter are passed after the value. + +For example, the filter ``{{ 42|myfilter(23) }}`` is called behind the +scenes as ``myfilter(42, 23)``. + +Jinja comes with some :ref:`built-in filters <builtin-filters>`. To use +a custom filter, write a function that takes at least a ``value`` +argument, then register it in :attr:`Environment.filters`. + +Here's a filter that formats datetime objects: + +.. code-block:: python + + def datetime_format(value, format="%H:%M %d-%m-%y"): + return value.strftime(format) + + environment.filters["datetime_format"] = datetime_format + +Now it can be used in templates: + +.. sourcecode:: jinja + + {{ article.pub_date|datetimeformat }} + {{ article.pub_date|datetimeformat("%B %Y") }} + +Some decorators are available to tell Jinja to pass extra information to +the filter. The object is passed as the first argument, making the value +being filtered the second argument. + +- :func:`pass_environment` passes the :class:`Environment`. +- :func:`pass_eval_context` passes the :ref:`eval-context`. +- :func:`pass_context` passes the current + :class:`~jinja2.runtime.Context`. + +Here's a filter that converts line breaks into HTML ``<br>`` and ``<p>`` +tags. It uses the eval context to check if autoescape is currently +enabled before escaping the input and marking the output safe. + +.. code-block:: python + + import re + from jinja2 import pass_eval_context + from markupsafe import Markup, escape + + @pass_eval_context + def nl2br(eval_ctx, value): + br = "<br>\n" + + if eval_ctx.autoescape: + value = escape(value) + br = Markup(br) + + result = "\n\n".join( + f"<p>{br.join(p.splitlines())}<\p>" + for p in re.split(r"(?:\r\n|\r(?!\n)|\n){2,}", value) + ) + return Markup(result) if autoescape else result + + +.. _writing-tests: + +Custom Tests +------------ + +Test are Python functions that take the value to the left of the test as +the first argument, and return ``True`` or ``False``. Arguments passed +to the test are passed after the value. + +For example, the test ``{{ 42 is even }}`` is called behind the scenes +as ``is_even(42)``. + +Jinja comes with some :ref:`built-in tests <builtin-tests>`. To use a +custom tests, write a function that takes at least a ``value`` argument, +then register it in :attr:`Environment.tests`. + +Here's a test that checks if a value is a prime number: + +.. code-block:: python + + import math + + def is_prime(n): + if n == 2: + return True + + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + + return True + + environment.tests["prime"] = is_prime + +Now it can be used in templates: + +.. sourcecode:: jinja + + {% if value is prime %} + {{ value }} is a prime number + {% else %} + {{ value }} is not a prime number + {% endif %} + +Some decorators are available to tell Jinja to pass extra information to +the filter. The object is passed as the first argument, making the value +being filtered the second argument. + +- :func:`pass_environment` passes the :class:`Environment`. +- :func:`pass_eval_context` passes the :ref:`eval-context`. +- :func:`pass_context` passes the current + :class:`~jinja2.runtime.Context`. + + +.. _eval-context: + +Evaluation Context +------------------ + +The evaluation context (short eval context or eval ctx) makes it +possible to activate and deactivate compiled features at runtime. + +Currently it is only used to enable and disable automatic escaping, but +it can be used by extensions as well. + +The ``autoescape`` setting should be checked on the evaluation context, +not the environment. The evaluation context will have the computed value +for the current template. + +Instead of ``pass_environment``: + +.. code-block:: python + + @pass_environment + def filter(env, value): + result = do_something(value) + + if env.autoescape: + result = Markup(result) + + return result + +Use ``pass_eval_context`` if you only need the setting: + +.. code-block:: python + + @pass_eval_context + def filter(eval_ctx, value): + result = do_something(value) + + if eval_ctx.autoescape: + result = Markup(result) + + return result + +Or use ``pass_context`` if you need other context behavior as well: + +.. code-block:: python + + @pass_context + def filter(context, value): + result = do_something(value) + + if context.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:: 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`. + + +.. _global-namespace: + +The Global Namespace +-------------------- + +The global namespace stores variables and functions that should be +available without needing to pass them to :meth:`Template.render`. They +are also available to templates that are imported or included without +context. Most applications should only use :attr:`Environment.globals`. + +:attr:`Environment.globals` are intended for data that is common to all +templates loaded by that environment. :attr:`Template.globals` are +intended for data that is common to all renders of that template, and +default to :attr:`Environment.globals` unless they're given in +:meth:`Environment.get_template`, etc. Data that is specific to a +render should be passed as context to :meth:`Template.render`. + +Only one set of globals is used during any specific rendering. If +templates A and B both have template globals, and B extends A, then +only B's globals are used for both when using ``b.render()``. + +Environment globals should not be changed after loading any templates, +and template globals should not be changed at any time after loading the +template. Changing globals after loading a template will result in +unexpected behavior as they may be shared between the environment and +other templates. + + +.. _low-level-api: + +Low Level API +------------- + +The low level API exposes functionality that can be useful to understand some +implementation details, debugging purposes or advanced :ref:`extension +<jinja-extensions>` techniques. Unless you know exactly what you are doing we +don't recommend using any of those. + +.. automethod:: Environment.lex + +.. automethod:: Environment.parse + +.. automethod:: Environment.preprocess + +.. automethod:: Template.new_context + +.. method:: Template.root_render_func(context) + + This is the low level render function. It's passed a :class:`Context` + that has to be created by :meth:`new_context` of the same template or + a compatible template. This render function is generated by the + compiler from the template code and returns a generator that yields + 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 Jinja versions will try not to + change it in a backwards incompatible way but modifications in the Jinja + core may shine through. For example if Jinja introduces a new AST node + in later versions that may be returned by :meth:`~Environment.parse`. + +The Meta API +------------ + +.. versionadded:: 2.2 + +The meta API returns some information about abstract syntax trees that +could help applications to implement more advanced template concepts. All +the functions of the meta API operate on an abstract syntax tree as +returned by the :meth:`Environment.parse` method. + +.. autofunction:: jinja2.meta.find_undeclared_variables + +.. autofunction:: jinja2.meta.find_referenced_templates diff --git a/docs/changes.rst b/docs/changes.rst new file mode 100644 index 0000000..955deaf --- /dev/null +++ b/docs/changes.rst @@ -0,0 +1,4 @@ +Changes +======= + +.. include:: ../CHANGES.rst diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..f65d462 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,53 @@ +from pallets_sphinx_themes import get_version +from pallets_sphinx_themes import ProjectLink + +# Project -------------------------------------------------------------- + +project = "Jinja" +copyright = "2007 Pallets" +author = "Pallets" +release, version = get_version("Jinja2") + +# General -------------------------------------------------------------- + +master_doc = "index" +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "pallets_sphinx_themes", + "sphinxcontrib.log_cabinet", + "sphinx_issues", +] +autodoc_typehints = "description" +intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)} +issues_github_path = "pallets/jinja" + +# HTML ----------------------------------------------------------------- + +html_theme = "jinja" +html_theme_options = {"index_sidebar_logo": False} +html_context = { + "project_links": [ + ProjectLink("Donate", "https://palletsprojects.com/donate"), + ProjectLink("PyPI Releases", "https://pypi.org/project/Jinja2/"), + ProjectLink("Source Code", "https://github.com/pallets/jinja/"), + ProjectLink("Issue Tracker", "https://github.com/pallets/jinja/issues/"), + ProjectLink("Website", "https://palletsprojects.com/p/jinja/"), + ProjectLink("Twitter", "https://twitter.com/PalletsTeam"), + ProjectLink("Chat", "https://discord.gg/pallets"), + ] +} +html_sidebars = { + "index": ["project.html", "localtoc.html", "searchbox.html", "ethicalads.html"], + "**": ["localtoc.html", "relations.html", "searchbox.html", "ethicalads.html"], +} +singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]} +html_static_path = ["_static"] +html_favicon = "_static/jinja-logo-sidebar.png" +html_logo = "_static/jinja-logo-sidebar.png" +html_title = f"Jinja Documentation ({version})" +html_show_sourcelink = False + +# LaTeX ---------------------------------------------------------------- + +latex_documents = [(master_doc, f"Jinja-{version}.tex", html_title, author, "manual")] diff --git a/docs/examples/cache_extension.py b/docs/examples/cache_extension.py new file mode 100644 index 0000000..46af67c --- /dev/null +++ b/docs/examples/cache_extension.py @@ -0,0 +1,54 @@ +from jinja2 import nodes +from jinja2.ext import Extension + + +class FragmentCacheExtension(Extension): + # a set of names that trigger the extension. + tags = {"cache"} + + def __init__(self, environment): + super().__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 = next(parser.stream).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 diff --git a/docs/examples/inline_gettext_extension.py b/docs/examples/inline_gettext_extension.py new file mode 100644 index 0000000..bf8b9db --- /dev/null +++ b/docs/examples/inline_gettext_extension.py @@ -0,0 +1,72 @@ +import re + +from jinja2.exceptions import TemplateSyntaxError +from jinja2.ext import Extension +from jinja2.lexer import count_newlines +from jinja2.lexer import Token + + +_outside_re = re.compile(r"\\?(gettext|_)\(") +_inside_re = re.compile(r"\\?[()]") + + +class InlineGettext(Extension): + """This extension implements support for inline gettext blocks:: + + <h1>_(Welcome)</h1> + <p>_(This is a paragraph)</p> + + Requires the i18n extension to be loaded and configured. + """ + + def filter_stream(self, stream): + paren_stack = 0 + + for token in stream: + if token.type != "data": + yield token + continue + + pos = 0 + lineno = token.lineno + + while True: + if not paren_stack: + match = _outside_re.search(token.value, pos) + else: + match = _inside_re.search(token.value, pos) + if match is None: + break + new_pos = match.start() + if new_pos > pos: + preval = token.value[pos:new_pos] + yield Token(lineno, "data", preval) + lineno += count_newlines(preval) + gtok = match.group() + if gtok[0] == "\\": + yield Token(lineno, "data", gtok[1:]) + elif not paren_stack: + yield Token(lineno, "block_begin", None) + yield Token(lineno, "name", "trans") + yield Token(lineno, "block_end", None) + paren_stack = 1 + else: + if gtok == "(" or paren_stack > 1: + yield Token(lineno, "data", gtok) + paren_stack += -1 if gtok == ")" else 1 + if not paren_stack: + yield Token(lineno, "block_begin", None) + yield Token(lineno, "name", "endtrans") + yield Token(lineno, "block_end", None) + pos = match.end() + + if pos < len(token.value): + yield Token(lineno, "data", token.value[pos:]) + + if paren_stack: + raise TemplateSyntaxError( + "unclosed gettext expression", + token.lineno, + stream.name, + stream.filename, + ) diff --git a/docs/extensions.rst b/docs/extensions.rst new file mode 100644 index 0000000..45ead3b --- /dev/null +++ b/docs/extensions.rst @@ -0,0 +1,423 @@ +.. _jinja-extensions: + +Extensions +========== + +Jinja supports extensions that can add extra filters, tests, globals or even +extend the parser. The main motivation of extensions is to move often used +code into a reusable class like adding support for internationalization. + + +Adding Extensions +----------------- + +Extensions are added to the Jinja environment at creation time. To add an +extension pass a list of extension classes or import paths to the +``extensions`` parameter of the :class:`~jinja2.Environment` constructor. The following +example creates a Jinja environment with the i18n extension loaded:: + + jinja_env = Environment(extensions=['jinja2.ext.i18n']) + +To add extensions after creation time, use the :meth:`~jinja2.Environment.add_extension` method:: + + jinja_env.add_extension('jinja2.ext.debug') + + +.. _i18n-extension: + +i18n Extension +-------------- + +**Import name:** ``jinja2.ext.i18n`` + +The i18n extension can be used in combination with `gettext`_ or +`Babel`_. When it's enabled, Jinja provides a ``trans`` statement that +marks a block as translatable and calls ``gettext``. + +After enabling, an application has to provide functions for ``gettext``, +``ngettext``, and optionally ``pgettext`` and ``npgettext``, either +globally or when rendering. A ``_()`` function is added as an alias to +the ``gettext`` function. + + +Environment Methods +~~~~~~~~~~~~~~~~~~~ + +After enabling the extension, the environment provides the following +additional methods: + +.. method:: jinja2.Environment.install_gettext_translations(translations, newstyle=False) + + Installs a translation globally for the environment. The + ``translations`` object must implement ``gettext``, ``ngettext``, + and optionally ``pgettext`` and ``npgettext``. + :class:`gettext.NullTranslations`, :class:`gettext.GNUTranslations`, + and `Babel`_\s ``Translations`` are supported. + + .. versionchanged:: 3.0 + Added ``pgettext`` and ``npgettext``. + + .. versionchanged:: 2.5 + Added new-style gettext support. + +.. method:: jinja2.Environment.install_null_translations(newstyle=False) + + Install no-op gettext functions. This is useful if you want to + prepare the application for internationalization but don't want to + implement the full system yet. + + .. versionchanged:: 2.5 Added new-style gettext support. + +.. method:: jinja2.Environment.install_gettext_callables(gettext, ngettext, newstyle=False, pgettext=None, npgettext=None) + + Install the given ``gettext``, ``ngettext``, ``pgettext``, and + ``npgettext`` callables into the environment. They should behave + exactly like :func:`gettext.gettext`, :func:`gettext.ngettext`, + :func:`gettext.pgettext` and :func:`gettext.npgettext`. + + If ``newstyle`` is activated, the callables are wrapped to work like + newstyle callables. See :ref:`newstyle-gettext` for more information. + + .. versionchanged:: 3.0 + Added ``pgettext`` and ``npgettext``. + + .. versionadded:: 2.5 + Added new-style gettext support. + +.. method:: jinja2.Environment.uninstall_gettext_translations() + + Uninstall the environment's globally installed translation. + +.. method:: jinja2.Environment.extract_translations(source) + + Extract localizable strings from the given template node or source. + + For every string found this function yields a ``(lineno, function, + message)`` tuple, where: + + - ``lineno`` is the number of the line on which the string was + found. + - ``function`` is the name of the ``gettext`` function used (if + the string was extracted from embedded Python code). + - ``message`` is the string itself, or a tuple of strings for + functions with multiple arguments. + + If `Babel`_ is installed, see :ref:`babel-integration` to extract + the strings. + +For a web application that is available in multiple languages but gives +all the users the same language (for example, multilingual forum +software installed for a French community), the translation may be +installed when the environment is created. + +.. code-block:: python + + translations = get_gettext_translations() + env = Environment(extensions=["jinja2.ext.i18n"]) + env.install_gettext_translations(translations) + +The ``get_gettext_translations`` function would return the translator +for the current configuration, for example by using ``gettext.find``. + +The usage of the ``i18n`` extension for template designers is covered in +:ref:`the template documentation <i18n-in-templates>`. + +.. _gettext: https://docs.python.org/3/library/gettext.html +.. _Babel: https://babel.pocoo.org/ + + +Whitespace Trimming +~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.10 + +Within ``{% trans %}`` blocks, it can be useful to trim line breaks and +whitespace so that the block of text looks like a simple string with +single spaces in the translation file. + +Linebreaks and surrounding whitespace can be automatically trimmed by +enabling the ``ext.i18n.trimmed`` :ref:`policy <ext-i18n-trimmed>`. + + +.. _newstyle-gettext: + +New Style Gettext +~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.5 + +New style gettext calls are less to type, less error prone, and support +autoescaping better. + +You can use "new style" gettext calls by setting +``env.newstyle_gettext = True`` or passing ``newstyle=True`` to +``env.install_translations``. They are fully supported by the Babel +extraction tool, but might not work as expected with other extraction +tools. + +With standard ``gettext`` calls, string formatting is a separate step +done with the ``|format`` filter. This requires duplicating work for +``ngettext`` calls. + +.. sourcecode:: jinja + + {{ gettext("Hello, World!") }} + {{ gettext("Hello, %(name)s!")|format(name=name) }} + {{ ngettext( + "%(num)d apple", "%(num)d apples", apples|count + )|format(num=apples|count) }} + {{ pgettext("greeting", "Hello, World!") }} + {{ npgettext( + "fruit", "%(num)d apple", "%(num)d apples", apples|count + )|format(num=apples|count) }} + +New style ``gettext`` make formatting part of the call, and behind the +scenes enforce more consistency. + +.. sourcecode:: jinja + + {{ gettext("Hello, World!") }} + {{ gettext("Hello, %(name)s!", name=name) }} + {{ ngettext("%(num)d apple", "%(num)d apples", apples|count) }} + {{ pgettext("greeting", "Hello, World!") }} + {{ npgettext("fruit", "%(num)d apple", "%(num)d apples", apples|count) }} + +The advantages of newstyle gettext are: + +- There's no separate formatting step, you don't have to remember to + use the ``|format`` filter. +- Only named placeholders are allowed. This solves a common problem + translators face because positional placeholders can't switch + positions meaningfully. Named placeholders always carry semantic + information about what value goes where. +- String formatting is used even if no placeholders are used, which + makes all strings use a consistent format. Remember to escape any + raw percent signs as ``%%``, such as ``100%%``. +- The translated string is marked safe, formatting performs escaping + as needed. Mark a parameter as ``|safe`` if it has already been + escaped. + + +Expression Statement +-------------------- + +**Import name:** ``jinja2.ext.do`` + +The "do" aka expression-statement extension adds a simple ``do`` tag to the +template engine that works like a variable expression but ignores the +return value. + +.. _loopcontrols-extension: + +Loop Controls +------------- + +**Import name:** ``jinja2.ext.loopcontrols`` + +This extension adds support for ``break`` and ``continue`` in loops. After +enabling, Jinja provides those two keywords which work exactly like in +Python. + +.. _with-extension: + +With Statement +-------------- + +**Import name:** ``jinja2.ext.with_`` + +.. versionchanged:: 2.9 + + This extension is now built-in and no longer does anything. + +.. _autoescape-extension: + +Autoescape Extension +-------------------- + +**Import name:** ``jinja2.ext.autoescape`` + +.. versionchanged:: 2.9 + + This extension was removed and is now built-in. Enabling the + extension no longer does anything. + + +.. _debug-extension: + +Debug Extension +--------------- + +**Import name:** ``jinja2.ext.debug`` + +Adds a ``{% debug %}`` tag to dump the current context as well as the +available filters and tests. This is useful to see what's available to +use in the template without setting up a debugger. + + +.. _writing-extensions: + +Writing Extensions +------------------ + +.. module:: jinja2.ext + +By writing extensions you can add custom tags to Jinja. This is a non-trivial +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 +Jinja template compiler which does not validate the node tree you are passing +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 Extensions +------------------ + +Cache +~~~~~ + +The following example implements a ``cache`` tag for Jinja by using the +`cachelib`_ library: + +.. literalinclude:: examples/cache_extension.py + :language: python + +And here is how you use it in an environment:: + + from jinja2 import Environment + from cachelib import SimpleCache + + env = Environment(extensions=[FragmentCacheExtension]) + env.fragment_cache = SimpleCache() + +Inside the template it's then possible to mark blocks as cacheable. The +following example caches a sidebar for 300 seconds: + +.. sourcecode:: html+jinja + + {% cache 'sidebar', 300 %} + <div class="sidebar"> + ... + </div> + {% endcache %} + +.. _cachelib: https://github.com/pallets/cachelib + + +Inline ``gettext`` +~~~~~~~~~~~~~~~~~~ + +The following example demonstrates using :meth:`Extension.filter_stream` +to parse calls to the ``_()`` gettext function inline with static data +without needing Jinja blocks. + +.. code-block:: html + + <h1>_(Welcome)</h1> + <p>_(This is a paragraph)</p> + +It requires the i18n extension to be loaded and configured. + +.. literalinclude:: examples/inline_gettext_extension.py + :language: python + + +Extension API +------------- + +Extension +~~~~~~~~~ + +Extensions always have to extend the :class:`jinja2.ext.Extension` class: + +.. autoclass:: Extension + :members: preprocess, filter_stream, parse, attr, call_method + + .. attribute:: identifier + + The identifier of the extension. This is always the true import name + of the extension class and must not be changed. + + .. attribute:: tags + + If the extension implements custom tags this is a set of tag names + the extension is listening for. + + +Parser +~~~~~~ + +The parser passed to :meth:`Extension.parse` provides ways to parse +expressions of different types. The following methods may be used by +extensions: + +.. autoclass:: jinja2.parser.Parser + :members: parse_expression, parse_tuple, parse_assign_target, + parse_statements, free_identifier, fail + + .. attribute:: filename + + The filename of the template the parser processes. This is **not** + the load name of the template. For the load name see :attr:`name`. + For templates that were not loaded form the file system this is + ``None``. + + .. attribute:: name + + The load name of the template. + + .. attribute:: stream + + The current :class:`~jinja2.lexer.TokenStream` + +.. autoclass:: jinja2.lexer.TokenStream + :members: push, look, eos, skip, __next__, next_if, skip_if, expect + + .. attribute:: current + + The current :class:`~jinja2.lexer.Token`. + +.. autoclass:: jinja2.lexer.Token + :members: test, test_any + + .. attribute:: lineno + + The line number of the token + + .. attribute:: type + + The type of the token. This string is interned so you may compare + it with arbitrary strings using the ``is`` operator. + + .. attribute:: value + + The value of the token. + +There is also a utility function in the lexer module that can count newline +characters in strings: + +.. autofunction:: jinja2.lexer.count_newlines + + +AST +~~~ + +The AST (Abstract Syntax Tree) is used to represent a template after parsing. +It's build of nodes that the compiler then converts into executable Python +code objects. Extensions that provide custom statements can return nodes to +execute custom Python code. + +The list below describes all nodes that are currently available. The AST may +change between Jinja versions but will stay backwards compatible. + +For more information have a look at the repr of :meth:`jinja2.Environment.parse`. + +.. module:: jinja2.nodes + +.. jinja:nodes:: jinja2.nodes.Node + +.. autoexception:: Impossible diff --git a/docs/faq.rst b/docs/faq.rst new file mode 100644 index 0000000..493dc38 --- /dev/null +++ b/docs/faq.rst @@ -0,0 +1,75 @@ +Frequently Asked Questions +========================== + + +Why is it called Jinja? +----------------------- + +"Jinja" is a Japanese `Shinto shrine`_, or temple, and temple and +template share a similar English pronunciation. It is not named after +the `city in Uganda`_. + +.. _Shinto shrine: https://en.wikipedia.org/wiki/Shinto_shrine +.. _city in Uganda: https://en.wikipedia.org/wiki/Jinja%2C_Uganda + + +How fast is Jinja? +------------------ + +Jinja is relatively fast among template engines because it compiles and +caches template code to Python code, so that the template does not need +to be parsed and interpreted each time. Rendering a template becomes as +close to executing a Python function as possible. + +Jinja also makes extensive use of caching. Templates are cached by name +after loading, so future uses of the template avoid loading. The +template loading itself uses a bytecode cache to avoid repeated +compiling. The caches can be external to persist across restarts. +Templates can also be precompiled and loaded as fast Python imports. + +We dislike benchmarks because they don't reflect real use. Performance +depends on many factors. Different engines have different default +configurations and tradeoffs that make it unclear how to set up a useful +comparison. Often, database access, API calls, and data processing have +a much larger effect on performance than the template engine. + + +Isn't it a bad idea to put logic in templates? +---------------------------------------------- + +Without a doubt you should try to remove as much logic from templates as +possible. With less logic, the template is easier to understand, has +fewer potential side effects, and is faster to compile and render. But a +template without any logic means processing must be done in code before +rendering. A template engine that does that is shipped with Python, +called :class:`string.Template`, and while it's definitely fast it's not +convenient. + +Jinja's features such as blocks, statements, filters, and function calls +make it much easier to write expressive templates, with very few +restrictions. Jinja doesn't allow arbitrary Python code in templates, or +every feature available in the Python language. This keeps the engine +easier to maintain, and keeps templates more readable. + +Some amount of logic is required in templates to keep everyone happy. +Too much logic in the template can make it complex to reason about and +maintain. It's up to you to decide how your application will work and +balance how much logic you want to put in the template. + + +Why is HTML escaping not the default? +------------------------------------- + +Jinja provides a feature that can be enabled to escape HTML syntax in +rendered templates. However, it is disabled by default. + +Jinja is a general purpose template engine, it is not only used for HTML +documents. You can generate plain text, LaTeX, emails, CSS, JavaScript, +configuration files, etc. HTML escaping wouldn't make sense for any of +these document types. + +While automatic escaping means that you are less likely have an XSS +problem, it also requires significant extra processing during compiling +and rendering, which can reduce performance. Jinja uses MarkupSafe for +escaping, which provides optimized C code for speed, but it still +introduces overhead to track escaping across methods and formatting. diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..4ce2071 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,29 @@ +.. rst-class:: hide-header + +Jinja +===== + +.. image:: _static/jinja-logo.png + :align: center + :target: https://palletsprojects.com/p/jinja/ + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + intro + api + sandbox + nativetypes + templates + extensions + integration + switching + tricks + faq + license + changes diff --git a/docs/integration.rst b/docs/integration.rst new file mode 100644 index 0000000..b945fb3 --- /dev/null +++ b/docs/integration.rst @@ -0,0 +1,94 @@ +Integration +=========== + + +Flask +----- + +The `Flask`_ web application framework, also maintained by Pallets, uses +Jinja templates by default. Flask sets up a Jinja environment and +template loader for you, and provides functions to easily render +templates from view functions. + +.. _Flask: https://flask.palletsprojects.com + + +Django +------ + +Django supports using Jinja as its template engine, see +https://docs.djangoproject.com/en/stable/topics/templates/#support-for-template-engines. + + +.. _babel-integration: + +Babel +----- + +Jinja provides support for extracting gettext messages from templates +via a `Babel`_ extractor entry point called +``jinja2.ext.babel_extract``. The support is implemented as part of the +:ref:`i18n-extension` extension. + +Gettext messages are extracted from both ``trans`` tags and code +expressions. + +To extract gettext messages from templates, the project needs a Jinja +section in its Babel extraction method `mapping file`_: + +.. sourcecode:: ini + + [jinja2: **/templates/**.html] + encoding = utf-8 + +The syntax related options of the :class:`Environment` are also +available as configuration values in the mapping file. For example, to +tell the extractor that templates use ``%`` as +``line_statement_prefix`` you can use this code: + +.. sourcecode:: ini + + [jinja2: **/templates/**.html] + encoding = utf-8 + line_statement_prefix = % + +:ref:`jinja-extensions` may also be defined by passing a comma separated +list of import paths as the ``extensions`` value. The i18n extension is +added automatically. + +Template syntax errors are ignored by default. The assumption is that +tests will catch syntax errors in templates. If you don't want to ignore +errors, add ``silent = false`` to the settings. + +.. _Babel: https://babel.readthedocs.io/ +.. _mapping file: https://babel.readthedocs.io/en/latest/messages.html#extraction-method-mapping-and-configuration + + +Pylons +------ + +It's easy to integrate Jinja into a `Pylons`_ application. + +The template engine is configured in ``config/environment.py``. The +configuration for Jinja looks something like this: + +.. code-block:: python + + from jinja2 import Environment, PackageLoader + config['pylons.app_globals'].jinja_env = Environment( + loader=PackageLoader('yourapplication', 'templates') + ) + +After that you can render Jinja templates by using the ``render_jinja`` +function from the ``pylons.templating`` module. + +Additionally it's a good idea to set the Pylons ``c`` object to strict +mode. By default attribute access on missing attributes on the ``c`` +object returns an empty string and not an undefined object. To change +this add this to ``config/environment.py``: + +.. code-block:: python + + config['pylons.strict_c'] = True + +.. _Pylons: https://pylonshq.com/ diff --git a/docs/intro.rst b/docs/intro.rst new file mode 100644 index 0000000..fd6f84f --- /dev/null +++ b/docs/intro.rst @@ -0,0 +1,63 @@ +Introduction +============ + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- Async support for generating templates that automatically handle + sync and async functions without extra syntax. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +Installation +------------ + +We recommend using the latest version of Python. Jinja supports Python +3.7 and newer. We also recommend using a `virtual environment`_ in order +to isolate your project dependencies from other projects and the system. + +.. _virtual environment: https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments + +Install the most recent Jinja version using pip: + +.. code-block:: text + + $ pip install Jinja2 + + +Dependencies +~~~~~~~~~~~~ + +These will be installed automatically when installing Jinja. + +- `MarkupSafe`_ escapes untrusted input when rendering templates to + avoid injection attacks. + +.. _MarkupSafe: https://markupsafe.palletsprojects.com/ + + +Optional Dependencies +~~~~~~~~~~~~~~~~~~~~~ + +These distributions will not be installed automatically. + +- `Babel`_ provides translation support in templates. + +.. _Babel: https://babel.pocoo.org/ diff --git a/docs/license.rst b/docs/license.rst new file mode 100644 index 0000000..a53a98c --- /dev/null +++ b/docs/license.rst @@ -0,0 +1,4 @@ +BSD-3-Clause License +==================== + +.. include:: ../LICENSE.rst diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..b162255 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/nativetypes.rst b/docs/nativetypes.rst new file mode 100644 index 0000000..1a08700 --- /dev/null +++ b/docs/nativetypes.rst @@ -0,0 +1,64 @@ +.. module:: jinja2.nativetypes + +.. _nativetypes: + +Native Python Types +=================== + +The default :class:`~jinja2.Environment` renders templates to strings. With +:class:`NativeEnvironment`, rendering a template produces a native Python type. +This is useful if you are using Jinja outside the context of creating text +files. For example, your code may have an intermediate step where users may use +templates to define values that will then be passed to a traditional string +environment. + +Examples +-------- + +Adding two values results in an integer, not a string with a number: + +>>> env = NativeEnvironment() +>>> t = env.from_string('{{ x + y }}') +>>> result = t.render(x=4, y=2) +>>> print(result) +6 +>>> print(type(result)) +int + +Rendering list syntax produces a list: + +>>> t = env.from_string('[{% for item in data %}{{ item + 1 }},{% endfor %}]') +>>> result = t.render(data=range(5)) +>>> print(result) +[1, 2, 3, 4, 5] +>>> print(type(result)) +list + +Rendering something that doesn't look like a Python literal produces a string: + +>>> t = env.from_string('{{ x }} * {{ y }}') +>>> result = t.render(x=4, y=2) +>>> print(result) +4 * 2 +>>> print(type(result)) +str + +Rendering a Python object produces that object as long as it is the only node: + +>>> class Foo: +... def __init__(self, value): +... self.value = value +... +>>> result = env.from_string('{{ x }}').render(x=Foo(15)) +>>> print(type(result).__name__) +Foo +>>> print(result.value) +15 + +API +--- + +.. autoclass:: NativeEnvironment([options]) + +.. autoclass:: NativeTemplate([options]) + :members: render diff --git a/docs/sandbox.rst b/docs/sandbox.rst new file mode 100644 index 0000000..fc9c31f --- /dev/null +++ b/docs/sandbox.rst @@ -0,0 +1,111 @@ +Sandbox +======= + +The Jinja sandbox can be used to render untrusted templates. Access to +attributes, method calls, operators, mutating data structures, and +string formatting can be intercepted and prohibited. + +.. code-block:: pycon + + >>> from jinja2.sandbox import SandboxedEnvironment + >>> env = SandboxedEnvironment() + >>> func = lambda: "Hello, Sandbox!" + >>> env.from_string("{{ func() }}").render(func=func) + 'Hello, Sandbox!' + >>> env.from_string("{{ func.__code__.co_code }}").render(func=func) + Traceback (most recent call last): + ... + SecurityError: access to attribute '__code__' of 'function' object is unsafe. + +A sandboxed environment can be useful, for example, to allow users of an +internal reporting system to create custom emails. You would document +what data is available in the templates, then the user would write a +template using that information. Your code would generate the report +data and pass it to the user's sandboxed template to render. + + +Security Considerations +----------------------- + +The sandbox alone is not a solution for perfect security. Keep these +things in mind when using the sandbox. + +Templates can still raise errors when compiled or rendered. Your code +should attempt to catch errors instead of crashing. + +It is possible to construct a relatively small template that renders to +a very large amount of output, which could correspond to a high use of +CPU or memory. You should run your application with limits on resources +such as CPU and memory to mitigate this. + +Jinja only renders text, it does not understand, for example, JavaScript +code. Depending on how the rendered template will be used, you may need +to do other postprocessing to restrict the output. + +Pass only the data that is relevant to the template. Avoid passing +global data, or objects with methods that have side effects. By default +the sandbox prevents private and internal attribute access. You can +override :meth:`~SandboxedEnvironment.is_safe_attribute` to further +restrict attributes access. Decorate methods with :func:`unsafe` to +prevent calling them from templates when passing objects as data. Use +:class:`ImmutableSandboxedEnvironment` to prevent modifying lists and +dictionaries. + + +API +--- + +.. module:: jinja2.sandbox + +.. autoclass:: SandboxedEnvironment([options]) + :members: is_safe_attribute, is_safe_callable, default_binop_table, + default_unop_table, intercepted_binops, intercepted_unops, + call_binop, call_unop + +.. autoclass:: ImmutableSandboxedEnvironment([options]) + +.. autoexception:: SecurityError + +.. autofunction:: unsafe + +.. autofunction:: is_internal_attribute + +.. autofunction:: modifies_known_mutable + + +Operator Intercepting +--------------------- + +For performance, Jinja outputs operators directly when compiling. This +means it's not possible to intercept operator behavior by overriding +:meth:`SandboxEnvironment.call <Environment.call>` by default, because +operator special methods are handled by the Python interpreter, and +might not correspond with exactly one method depending on the operator's +use. + +The sandbox can instruct the compiler to output a function to intercept +certain operators instead. Override +:attr:`SandboxedEnvironment.intercepted_binops` and +:attr:`SandboxedEnvironment.intercepted_unops` with the operator symbols +you want to intercept. The compiler will replace the symbols with calls +to :meth:`SandboxedEnvironment.call_binop` and +:meth:`SandboxedEnvironment.call_unop` instead. The default +implementation of those methods will use +:attr:`SandboxedEnvironment.binop_table` and +:attr:`SandboxedEnvironment.unop_table` to translate operator symbols +into :mod:`operator` functions. + +For example, the power (``**``) operator can be disabled: + +.. code-block:: python + + from jinja2.sandbox import SandboxedEnvironment + + class MyEnvironment(SandboxedEnvironment): + intercepted_binops = frozenset(["**"]) + + def call_binop(self, context, operator, left, right): + if operator == "**": + return self.undefined("The power (**) operator is unavailable.") + + return super().call_binop(self, context, operator, left, right) diff --git a/docs/switching.rst b/docs/switching.rst new file mode 100644 index 0000000..caa35c3 --- /dev/null +++ b/docs/switching.rst @@ -0,0 +1,181 @@ +Switching From Other Template Engines +===================================== + +This is a brief guide on some of the differences between Jinja syntax +and other template languages. See :doc:`/templates` for a comprehensive +guide to Jinja syntax and features. + + +Django +------ + +If you have previously worked with Django templates, you should find +Jinja very familiar. Many of the syntax elements look and work the same. +However, Jinja provides some more syntax elements, and some work a bit +differently. + +This section covers the template changes. The API, including extension +support, is fundamentally different so it won't be covered here. + +Django supports using Jinja as its template engine, see +https://docs.djangoproject.com/en/stable/topics/templates/#support-for-template-engines. + + +Method Calls +~~~~~~~~~~~~ + +In Django, methods are called implicitly, without parentheses. + +.. code-block:: django + + {% for page in user.get_created_pages %} + ... + {% endfor %} + +In Jinja, using parentheses is required for calls, like in Python. This +allows you to pass variables to the method, which is not possible +in Django. This syntax is also used for calling macros. + +.. code-block:: jinja + + {% for page in user.get_created_pages() %} + ... + {% endfor %} + + +Filter Arguments +~~~~~~~~~~~~~~~~ + +In Django, one literal value can be passed to a filter after a colon. + +.. code-block:: django + + {{ items|join:", " }} + +In Jinja, filters can take any number of positional and keyword +arguments in parentheses, like function calls. Arguments can also be +variables instead of literal values. + +.. code-block:: jinja + + {{ items|join(", ") }} + + +Tests +~~~~~ + +In addition to filters, Jinja also has "tests" used with the ``is`` +operator. This operator is not the same as the Python operator. + +.. code-block:: jinja + + {% if user.user_id is odd %} + {{ user.username|e }} is odd + {% else %} + hmm. {{ user.username|e }} looks pretty normal + {% endif %} + +Loops +~~~~~ + +In Django, the special variable for the loop context is called +``forloop``, and the ``empty`` is used for no loop items. + +.. code-block:: django + + {% for item in items %} + {{ item }} + {% empty %} + No items! + {% endfor %} + +In Jinja, the special variable for the loop context is called ``loop``, +and the ``else`` block is used for no loop items. + +.. code-block:: jinja + + {% for item in items %} + {{ loop.index}}. {{ item }} + {% else %} + No items! + {% endfor %} + + +Cycle +~~~~~ + +In Django, the ``{% cycle %}`` can be used in a for loop to alternate +between values per loop. + +.. code-block:: django + + {% for user in users %} + <li class="{% cycle 'odd' 'even' %}">{{ user }}</li> + {% endfor %} + +In Jinja, the ``loop`` context has a ``cycle`` method. + +.. code-block:: jinja + + {% for user in users %} + <li class="{{ loop.cycle('odd', 'even') }}">{{ user }}</li> + {% endfor %} + +A cycler can also be assigned to a variable and used outside or across +loops with the ``cycle()`` global function. + + +Mako +---- + +You can configure Jinja to look more like Mako: + +.. code-block:: python + + env = Environment( + block_start_string="<%", + block_end_string="%>", + variable_start_string="${", + variable_end_string="}", + comment_start_string="<%doc>", + commend_end_string="</%doc>", + line_statement_prefix="%", + line_comment_prefix="##", + ) + +With an environment configured like that, Jinja should be able to +interpret a small subset of Mako templates without any changes. + +Jinja does not support embedded Python code, so you would have to move +that out of the template. You could either process the data with the +same code before rendering, or add a global function or filter to the +Jinja environment. + +The syntax for defs (which are called macros in Jinja) and template +inheritance is different too. + +The following Mako template: + +.. code-block:: mako + + <%inherit file="layout.html" /> + <%def name="title()">Page Title</%def> + <ul> + % for item in list: + <li>${item}</li> + % endfor + </ul> + +Looks like this in Jinja with the above configuration: + +.. code-block:: jinja + + <% extends "layout.html" %> + <% block title %>Page Title<% endblock %> + <% block body %> + <ul> + % for item in list: + <li>${item}</li> + % endfor + </ul> + <% endblock %> diff --git a/docs/templates.rst b/docs/templates.rst new file mode 100644 index 0000000..7a64750 --- /dev/null +++ b/docs/templates.rst @@ -0,0 +1,1949 @@ +.. py:currentmodule:: jinja2 +.. highlight:: html+jinja + +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 can +be slightly different from the code presented here in terms of delimiters and +behavior of undefined values. + + +Synopsis +-------- + +A Jinja template is simply a text file. Jinja can generate any text-based +format (HTML, XML, CSV, LaTeX, etc.). A Jinja template doesn't need to have a +specific extension: ``.html``, ``.xml``, or any other extension is just fine. + +A template contains **variables** and/or **expressions**, which get replaced +with values when a template is *rendered*; 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 using the default +Jinja configuration. We will cover the details later in this document:: + + <!DOCTYPE html> + <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 }} + + {# a comment #} + </body> + </html> + +The following example shows the default configuration settings. An application +developer can change the syntax configuration from ``{% foo %}`` to ``<% foo +%>``, or something similar. + +There are a few kinds of delimiters. The default Jinja delimiters are +configured as follows: + +* ``{% ... %}`` for :ref:`Statements <list-of-control-structures>` +* ``{{ ... }}`` for :ref:`Expressions` to print to the template output +* ``{# ... #}`` for :ref:`Comments` not included in the template output + +:ref:`Line Statements and Comments <line-statements>` are also possible, +though they don't have default prefix characters. To use them, set +``line_statement_prefix`` and ``line_comment_prefix`` when creating the +:class:`~jinja2.Environment`. + + +Template File Extension +~~~~~~~~~~~~~~~~~~~~~~~ + +As stated above, any file can be loaded as a template, regardless of +file extension. Adding a ``.jinja`` extension, like ``user.html.jinja`` +may make it easier for some IDEs or editor plugins, but is not required. +Autoescaping, introduced later, can be applied based on file extension, +so you'll need to take the extra suffix into account in that case. + +Another good heuristic for identifying templates is that they are in a +``templates`` folder, regardless of extension. This is a common layout +for projects. + + +.. _variables: + +Variables +--------- + +Template variables are defined by the context dictionary passed to the +template. + +You can mess around with the variables in templates provided they are passed in +by the application. Variables may have attributes or elements on them you can +access too. What attributes a variable has depends heavily on the application +providing that variable. + +You can use a dot (``.``) to access attributes of a variable in addition +to the standard Python ``__getitem__`` "subscript" syntax (``[]``). + +The following lines do the same thing:: + + {{ foo.bar }} + {{ foo['bar'] }} + +It's important to know that the outer double-curly braces are *not* part of the +variable, but the print statement. If you access variables inside tags don't +put the braces around them. + +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 to evaluate to an empty string if +printed or iterated over, and to fail for every other operation. + +.. _notes-on-subscriptions: + +.. admonition:: Implementation + + For the sake of convenience, ``foo.bar`` in Jinja does the following + things on the Python layer: + + - check for an attribute called `bar` on `foo` + (``getattr(foo, 'bar')``) + - if there is not, check for an item ``'bar'`` in `foo` + (``foo.__getitem__('bar')``) + - if there is not, return an undefined object. + + ``foo['bar']`` works mostly the same with a small difference in sequence: + + - check for an item ``'bar'`` in `foo`. + (``foo.__getitem__('bar')``) + - if there is not, check for an attribute called `bar` on `foo`. + (``getattr(foo, 'bar')``) + - if there is not, return an undefined object. + + This is important if an object has an item and attribute with the same + name. Additionally, the :func:`attr` filter only looks up attributes. + +.. _filters: + +Filters +------- + +Variables can be 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. + +For example, ``{{ name|striptags|title }}`` will remove all HTML Tags from +variable `name` and title-case the output (``title(striptags(name))``). + +Filters that accept arguments have parentheses around the arguments, just like +a function call. For example: ``{{ listx|join(', ') }}`` will join a list with +commas (``str.join(', ', listx)``). + +The :ref:`builtin-filters` below describes all the builtin filters. + +.. _tests: + +Tests +----- + +Beside filters, there are also so-called "tests" available. Tests can be used +to test a variable against a common expression. To test a variable or +expression, you add `is` plus the name of the test after the variable. For +example, to find out if a variable is defined, you can do ``name is defined``, +which will then return true or false depending on whether `name` is defined +in the current template context. + +Tests can accept arguments, too. If the test only takes one argument, you can +leave out the parentheses. For example, the following two +expressions do the same thing:: + + {% if loop.index is divisibleby 3 %} + {% if loop.index is divisibleby(3) %} + +The :ref:`builtin-tests` below describes all the builtin tests. + + +.. _comments: + +Comments +-------- + +To comment-out part of a line in a template, use the comment syntax which is +by default set to ``{# ... #}``. This is useful to comment out parts of the +template for debugging or to add information for other template designers or +yourself:: + + {# note: commented-out template because we no longer use this + {% for user in users %} + ... + {% endfor %} + #} + + +Whitespace Control +------------------ + +In the default configuration: + +* a single trailing newline is stripped if present +* other whitespace (spaces, tabs, newlines etc.) is returned unchanged + +If an application configures Jinja to `trim_blocks`, the first newline after a +template tag is removed automatically (like in PHP). The `lstrip_blocks` +option can also be set to strip tabs and spaces from the beginning of a +line to the start of a block. (Nothing will be stripped if there are +other characters before the start of the block.) + +With both `trim_blocks` and `lstrip_blocks` enabled, you can put block tags +on their own lines, and the entire block line will be removed when +rendered, preserving the whitespace of the contents. For example, +without the `trim_blocks` and `lstrip_blocks` options, this template:: + + <div> + {% if True %} + yay + {% endif %} + </div> + +gets rendered with blank lines inside the div:: + + <div> + + yay + + </div> + +But with both `trim_blocks` and `lstrip_blocks` enabled, the template block +lines are removed and other whitespace is preserved:: + + <div> + yay + </div> + +You can manually disable the `lstrip_blocks` behavior by putting a +plus sign (``+``) at the start of a block:: + + <div> + {%+ if something %}yay{% endif %} + </div> + +Similarly, you can manually disable the ``trim_blocks`` behavior by +putting a plus sign (``+``) at the end of a block:: + + <div> + {% if something +%} + yay + {% endif %} + </div> + +You can also strip whitespace in templates by hand. If you add a minus +sign (``-``) to the start or end of a block (e.g. a :ref:`for-loop` tag), a +comment, or a variable expression, the whitespaces before or after +that block will be removed:: + + {% for item in seq -%} + {{ item }} + {%- endfor %} + +This will yield all elements without whitespace between them. If `seq` was +a list of numbers from ``1`` to ``9``, the output would be ``123456789``. + +If :ref:`line-statements` are enabled, they strip leading whitespace +automatically up to the beginning of the line. + +By default, Jinja also removes trailing newlines. To keep single +trailing newlines, configure Jinja to `keep_trailing_newline`. + +.. admonition:: Note + + You must not add whitespace between the tag and the minus sign. + + **valid**:: + + {%- if foo -%}...{% endif %} + + **invalid**:: + + {% - if foo - %}...{% endif %} + + +Escaping +-------- + +It is sometimes desirable -- even necessary -- to have Jinja ignore parts +it would otherwise handle as variables or blocks. For example, if, with +the default syntax, you want to use ``{{`` as a raw string in a template and +not start a variable, you have to use a trick. + +The easiest way to output a literal variable delimiter (``{{``) is by using a +variable expression:: + + {{ '{{' }} + +For bigger sections, it makes sense to mark a block `raw`. For example, to +include example Jinja syntax in a template, you can use this snippet:: + + {% raw %} + <ul> + {% for item in seq %} + <li>{{ item }}</li> + {% endfor %} + </ul> + {% endraw %} + +.. admonition:: Note + + Minus sign at the end of ``{% raw -%}`` tag cleans all the spaces and newlines + preceding the first character of your raw data. + + +.. _line-statements: + +Line Statements +--------------- + +If line statements are enabled by the application, it's possible to mark a +line as a statement. For example, if the line statement prefix is configured +to ``#``, the following two examples are equivalent:: + + <ul> + # for item in seq + <li>{{ item }}</li> + # endfor + </ul> + + <ul> + {% for item in seq %} + <li>{{ item }}</li> + {% endfor %} + </ul> + +The line statement prefix can appear anywhere on the line as long as no text +precedes it. For better readability, statements that start a block (such as +`for`, `if`, `elif` etc.) may end with a colon:: + + # for item in seq: + ... + # endfor + + +.. admonition:: Note + + Line statements can span multiple lines if there are open parentheses, + braces or brackets:: + + <ul> + # for href, caption in [('index.html', 'Index'), + ('about.html', 'About')]: + <li><a href="{{ href }}">{{ caption }}</a></li> + # endfor + </ul> + +Since Jinja 2.2, line-based comments are available as well. For example, if +the line-comment prefix is configured to be ``##``, everything from ``##`` to +the end of the line is ignored (excluding the newline sign):: + + # for item in seq: + <li>{{ item }}</li> ## this comment is ignored + # endfor + + +.. _template-inheritance: + +Template Inheritance +-------------------- + +The most powerful part of Jinja is template inheritance. Template inheritance +allows you to build a base "skeleton" template that contains all the common +elements of your site and defines **blocks** that child templates can override. + +Sounds complicated but is very basic. It's easiest to understand it by starting +with an example. + + +Base Template +~~~~~~~~~~~~~ + +This template, which we'll call ``base.html``, defines a simple HTML skeleton +document that you might use for a simple two-column page. It's the job of +"child" templates to fill the empty blocks with content:: + + <!DOCTYPE html> + <html lang="en"> + <head> + {% block head %} + <link rel="stylesheet" href="style.css" /> + <title>{% block title %}{% endblock %} - My Webpage</title> + {% endblock %} + </head> + <body> + <div id="content">{% block content %}{% endblock %}</div> + <div id="footer"> + {% block footer %} + © Copyright 2008 by <a href="http://domain.invalid/">you</a>. + {% endblock %} + </div> + </body> + </html> + +In this example, the ``{% block %}`` tags define four blocks that child templates +can fill in. All the `block` tag does is tell the template engine that a +child template may override those placeholders in the template. + +``block`` tags can be inside other blocks such as ``if``, but they will +always be executed regardless of if the ``if`` block is actually +rendered. + +Child Template +~~~~~~~~~~~~~~ + +A child template might look like this:: + + {% extends "base.html" %} + {% block title %}Index{% endblock %} + {% block head %} + {{ super() }} + <style type="text/css"> + .important { color: #336699; } + </style> + {% endblock %} + {% block content %} + <h1>Index</h1> + <p class="important"> + Welcome to my awesome homepage. + </p> + {% endblock %} + +The ``{% extends %}`` tag is the key here. It tells the template engine that +this template "extends" another template. When the template system evaluates +this template, it first locates the parent. The extends tag should be the +first tag in the template. Everything before it is printed out normally and +may cause confusion. For details about this behavior and how to take +advantage of it, see :ref:`null-default-fallback`. Also a block will always be +filled in regardless of whether the surrounding condition is evaluated to be true +or false. + +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 a slash:: + + {% extends "layout/default.html" %} + +But this behavior can depend on the application embedding Jinja. Note that +since the child template doesn't define the ``footer`` block, the value from +the parent template is used instead. + +You can't define multiple ``{% block %}`` tags with the same name in the +same template. This limitation exists because a block tag works in "both" +directions. That is, a block tag doesn't just provide a placeholder to fill +- it also defines the content that fills the placeholder in the *parent*. +If there were two similarly-named ``{% block %}`` tags in a template, +that template's parent wouldn't know which one of the blocks' content to use. + +If you want to print a block multiple times, you can, however, use the special +`self` variable and call the block with that name:: + + <title>{% block title %}{% endblock %}</title> + <h1>{{ self.title() }}</h1> + {% block body %}{% endblock %} + + +Super Blocks +~~~~~~~~~~~~ + +It's possible to render the contents of the parent block by calling ``super()``. +This gives back the results of the parent block:: + + {% block sidebar %} + <h3>Table Of Contents</h3> + ... + {{ super() }} + {% endblock %} + + +Nesting extends +~~~~~~~~~~~~~~~ + +In the case of multiple levels of ``{% extends %}``, +``super`` references may be chained (as in ``super.super()``) +to skip levels in the inheritance tree. + +For example:: + + # parent.tmpl + body: {% block body %}Hi from parent.{% endblock %} + + # child.tmpl + {% extends "parent.tmpl" %} + {% block body %}Hi from child. {{ super() }}{% endblock %} + + # grandchild1.tmpl + {% extends "child.tmpl" %} + {% block body %}Hi from grandchild1.{% endblock %} + + # grandchild2.tmpl + {% extends "child.tmpl" %} + {% block body %}Hi from grandchild2. {{ super.super() }} {% endblock %} + + +Rendering ``child.tmpl`` will give +``body: Hi from child. Hi from parent.`` + +Rendering ``grandchild1.tmpl`` will give +``body: Hi from grandchild1.`` + +Rendering ``grandchild2.tmpl`` will give +``body: Hi from grandchild2. Hi from parent.`` + + +Named Block End-Tags +~~~~~~~~~~~~~~~~~~~~ + +Jinja allows you to put the name of the block after the end tag for better +readability:: + + {% block sidebar %} + {% block inner_sidebar %} + ... + {% endblock inner_sidebar %} + {% endblock sidebar %} + +However, the name after the `endblock` word must match the block name. + + +Block Nesting and Scope +~~~~~~~~~~~~~~~~~~~~~~~ + +Blocks can be nested for more complex layouts. However, per default blocks +may not access variables from outer scopes:: + + {% for item in seq %} + <li>{% block loop_item %}{{ item }}{% endblock %}</li> + {% endfor %} + +This example would output empty ``<li>`` items because `item` is unavailable +inside the block. The reason for this is that if the block is replaced by +a child template, a variable would appear that was not defined in the block or +passed to the context. + +Starting with Jinja 2.2, you can explicitly specify that variables are +available in a block by setting the block to "scoped" by adding the `scoped` +modifier to a block declaration:: + + {% for item in seq %} + <li>{% block loop_item scoped %}{{ item }}{% endblock %}</li> + {% endfor %} + +When overriding a block, the `scoped` modifier does not have to be provided. + + +Required Blocks +~~~~~~~~~~~~~~~ + +Blocks can be marked as ``required``. They must be overridden at some +point, but not necessarily by the direct child template. Required blocks +may only contain space and comments, and they cannot be rendered +directly. + +.. code-block:: jinja + :caption: ``page.txt`` + + {% block body required %}{% endblock %} + +.. code-block:: jinja + :caption: ``issue.txt`` + + {% extends "page.txt" %} + +.. code-block:: jinja + :caption: ``bug_report.txt`` + + {% extends "issue.txt" %} + {% block body %}Provide steps to demonstrate the bug.{% endblock %} + +Rendering ``page.txt`` or ``issue.txt`` will raise +``TemplateRuntimeError`` because they don't override the ``body`` block. +Rendering ``bug_report.txt`` will succeed because it does override the +block. + +When combined with ``scoped``, the ``required`` modifier must be placed +*after* the scoped modifier. Here are some valid examples: + +.. code-block:: jinja + + {% block body scoped %}{% endblock %} + {% block body required %}{% endblock %} + {% block body scoped required %}{% endblock %} + + +Template Objects +~~~~~~~~~~~~~~~~ + +``extends``, ``include``, and ``import`` can take a template object +instead of the name of a template to load. This could be useful in some +advanced situations, since you can use Python code to load a template +first and pass it in to ``render``. + +.. code-block:: python + + if debug_mode: + layout = env.get_template("debug_layout.html") + else: + layout = env.get_template("layout.html") + + user_detail = env.get_template("user/detail.html", layout=layout) + +.. code-block:: jinja + + {% extends layout %} + +Note how ``extends`` is passed the variable with the template object +that was passed to ``render``, instead of a string. + + +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: + +a. manually escaping each variable; or +b. automatically escaping everything by default. + +Jinja supports both. What is used depends on the application configuration. +The default configuration is no automatic escaping; for various reasons: + +- Escaping everything except for safe values will also mean that Jinja is + escaping variables known to not include HTML (e.g. numbers, booleans) + which can be 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 +**SHOULD** 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. Variables and expressions +can be marked as safe either in: + +a. The context dictionary by the application with + :class:`markupsafe.Markup` +b. The template, with the ``|safe`` filter. + +If a string that you marked safe is passed through other Python code +that doesn't understand that mark, it may get lost. Be aware of when +your data is marked safe and how it is processed before arriving at the +template. + +If a value has been escaped but is not marked safe, auto-escaping will +still take place and result in double-escaped characters. If you know +you have data that is already safe but not marked, be sure to wrap it in +``Markup`` or use the ``|safe`` filter. + +Jinja functions (macros, `super`, `self.BLOCKNAME`) always return template +data that is marked as safe. + +String literals in templates with automatic escaping are considered +unsafe because native Python strings are not safe. + +.. _list-of-control-structures: + +List of Control Structures +-------------------------- + +A control structure refers to all those things that control the flow of a +program - conditionals (i.e. if/elif/else), for-loops, as well as things like +macros and blocks. With the default syntax, control structures appear inside +``{% ... %}`` blocks. + +.. _for-loop: + +For +~~~ + +Loop over each item in a sequence. For example, to display a list of users +provided in a variable called `users`:: + + <h1>Members</h1> + <ul> + {% for user in users %} + <li>{{ user.username|e }}</li> + {% endfor %} + </ul> + +As variables in templates retain their object properties, it is possible to +iterate over containers like `dict`:: + + <dl> + {% for key, value in my_dict.items() %} + <dt>{{ key|e }}</dt> + <dd>{{ value|e }}</dd> + {% endfor %} + </dl> + +Python dicts may not be in the order you want to display them in. If +order matters, use the ``|dictsort`` filter. + +.. code-block:: jinja + + <dl> + {% for key, value in my_dict | dictsort %} + <dt>{{ key|e }}</dt> + <dd>{{ value|e }}</dd> + {% endfor %} + </dl> + +Inside of a for-loop block, you can access some special variables: + ++-----------------------+---------------------------------------------------+ +| Variable | Description | ++=======================+===================================================+ +| `loop.index` | The current iteration of the loop. (1 indexed) | ++-----------------------+---------------------------------------------------+ +| `loop.index0` | The current iteration of the loop. (0 indexed) | ++-----------------------+---------------------------------------------------+ +| `loop.revindex` | The number of iterations from the end of the loop | +| | (1 indexed) | ++-----------------------+---------------------------------------------------+ +| `loop.revindex0` | The number of iterations from the end of the loop | +| | (0 indexed) | ++-----------------------+---------------------------------------------------+ +| `loop.first` | True if first iteration. | ++-----------------------+---------------------------------------------------+ +| `loop.last` | True if last iteration. | ++-----------------------+---------------------------------------------------+ +| `loop.length` | The number of items in the sequence. | ++-----------------------+---------------------------------------------------+ +| `loop.cycle` | A helper function to cycle between a list of | +| | sequences. See the explanation below. | ++-----------------------+---------------------------------------------------+ +| `loop.depth` | Indicates how deep in a recursive loop | +| | the rendering currently is. Starts at level 1 | ++-----------------------+---------------------------------------------------+ +| `loop.depth0` | Indicates how deep in a recursive loop | +| | the rendering currently is. Starts at level 0 | ++-----------------------+---------------------------------------------------+ +| `loop.previtem` | The item from the previous iteration of the loop. | +| | Undefined during the first iteration. | ++-----------------------+---------------------------------------------------+ +| `loop.nextitem` | The item from the following iteration of the loop.| +| | Undefined during the last iteration. | ++-----------------------+---------------------------------------------------+ +| `loop.changed(*val)` | True if previously called with a different value | +| | (or not called at all). | ++-----------------------+---------------------------------------------------+ + +Within a for-loop, it's possible to cycle among a list of strings/variables +each time through the loop by using the special `loop.cycle` helper:: + + {% for row in rows %} + <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li> + {% endfor %} + +Since Jinja 2.1, an extra `cycle` helper exists that allows loop-unbound +cycling. For more information, have a look at the :ref:`builtin-globals`. + +.. _loop-filtering: + +Unlike in Python, it's not possible to `break` or `continue` in a loop. You +can, however, filter the sequence during iteration, which allows you to skip +items. The following example skips all the users which are hidden:: + + {% for user in users if not user.hidden %} + <li>{{ user.username|e }}</li> + {% endfor %} + +The advantage is that the special `loop` variable will count correctly; thus +not counting the users not iterated over. + +If no iteration took place because the sequence was empty or the filtering +removed all the items from the sequence, you can render a default block +by using `else`:: + + <ul> + {% for user in users %} + <li>{{ user.username|e }}</li> + {% else %} + <li><em>no users found</em></li> + {% endfor %} + </ul> + +Note that, in Python, `else` blocks are executed whenever the corresponding +loop **did not** `break`. Since Jinja loops cannot `break` anyway, +a slightly different behavior of the `else` keyword was chosen. + +It is also possible to use loops recursively. This is useful if you are +dealing with recursive data such as sitemaps or RDFa. +To use loops recursively, you basically have to add the `recursive` modifier +to the loop definition and call the `loop` variable with the new iterable +where you want to recurse. + +The following example implements a sitemap with recursive loops:: + + <ul class="sitemap"> + {%- for item in sitemap recursive %} + <li><a href="{{ item.href|e }}">{{ item.title }}</a> + {%- if item.children -%} + <ul class="submenu">{{ loop(item.children) }}</ul> + {%- endif %}</li> + {%- endfor %} + </ul> + +The `loop` variable always refers to the closest (innermost) loop. If we +have more than one level of loops, we can rebind the variable `loop` by +writing `{% set outer_loop = loop %}` after the loop that we want to +use recursively. Then, we can call it using `{{ outer_loop(...) }}` + +Please note that assignments in loops will be cleared at the end of the +iteration and cannot outlive the loop scope. Older versions of Jinja had +a bug where in some circumstances it appeared that assignments would work. +This is not supported. See :ref:`assignments` for more information about +how to deal with this. + +If all you want to do is check whether some value has changed since the +last iteration or will change in the next iteration, you can use `previtem` +and `nextitem`:: + + {% for value in values %} + {% if loop.previtem is defined and value > loop.previtem %} + The value just increased! + {% endif %} + {{ value }} + {% if loop.nextitem is defined and loop.nextitem > value %} + The value will increase even more! + {% endif %} + {% endfor %} + +If you only care whether the value changed at all, using `changed` is even +easier:: + + {% for entry in entries %} + {% if loop.changed(entry.category) %} + <h2>{{ entry.category }}</h2> + {% endif %} + <p>{{ entry.message }}</p> + {% endfor %} + +.. _if: + +If +~~ + +The `if` statement in Jinja is comparable with the Python if statement. +In the simplest form, you can use it to test if a variable is defined, not +empty and not false:: + + {% if users %} + <ul> + {% for user in users %} + <li>{{ user.username|e }}</li> + {% endfor %} + </ul> + {% endif %} + +For multiple branches, `elif` and `else` can be used like in Python. You can +use more complex :ref:`expressions` there, too:: + + {% if kenny.sick %} + Kenny is sick. + {% elif kenny.dead %} + You killed Kenny! You bastard!!! + {% else %} + Kenny looks okay --- so far + {% endif %} + +If can also be used as an :ref:`inline expression <if-expression>` and for +:ref:`loop filtering <loop-filtering>`. + +.. _macros: + +Macros +~~~~~~ + +Macros are comparable with functions in regular programming languages. They +are useful to put often used idioms into reusable functions to not repeat +yourself ("DRY"). + +Here's a small example of a macro that renders a form element:: + + {% macro input(name, value='', type='text', size=20) -%} + <input type="{{ type }}" name="{{ name }}" value="{{ + value|e }}" size="{{ size }}"> + {%- endmacro %} + +The macro can then be called like a function in the namespace:: + + <p>{{ input('username') }}</p> + <p>{{ input('password', type='password') }}</p> + +If the macro was defined in a different template, you have to +:ref:`import <import>` it first. + +Inside macros, you have access to three special variables: + +`varargs` + If more positional arguments are passed to the macro than accepted by the + macro, they end up in the special `varargs` variable as a list of values. + +`kwargs` + Like `varargs` but for keyword arguments. All unconsumed keyword + arguments are stored in this special variable. + +`caller` + If the macro was called from a :ref:`call<call>` tag, the caller is stored + in this variable as a callable macro. + +Macros also expose some of their internal details. The following attributes +are available on a macro object: + +`name` + The name of the macro. ``{{ input.name }}`` will print ``input``. + +`arguments` + A tuple of the names of arguments the macro accepts. + +`catch_kwargs` + This is `true` if the macro accepts extra keyword arguments (i.e.: accesses + the special `kwargs` variable). + +`catch_varargs` + This is `true` if the macro accepts extra positional arguments (i.e.: + accesses the special `varargs` variable). + +`caller` + This is `true` if the macro accesses the special `caller` variable and may + be called from a :ref:`call<call>` tag. + +If a macro name starts with an underscore, it's not exported and can't +be imported. + +Due to how scopes work in Jinja, a macro in a child template does not +override a macro in a parent template. The following will output +"LAYOUT", not "CHILD". + +.. code-block:: jinja + :caption: ``layout.txt`` + + {% macro foo() %}LAYOUT{% endmacro %} + {% block body %}{% endblock %} + +.. code-block:: jinja + :caption: ``child.txt`` + + {% extends 'layout.txt' %} + {% macro foo() %}CHILD{% endmacro %} + {% block body %}{{ foo() }}{% endblock %} + + +.. _call: + +Call +~~~~ + +In some cases it can be useful to pass a macro to another macro. For this +purpose, you can use the special `call` block. The following example shows +a macro that takes advantage of the call functionality and how it can be +used:: + + {% macro render_dialog(title, class='dialog') -%} + <div class="{{ class }}"> + <h2>{{ title }}</h2> + <div class="contents"> + {{ caller() }} + </div> + </div> + {%- endmacro %} + + {% call render_dialog('Hello World') %} + This is a simple dialog rendered by using a macro and + a call block. + {% endcall %} + +It's also possible to pass arguments back to the call block. This makes it +useful as a replacement for loops. Generally speaking, a call block works +exactly like a macro without a name. + +Here's an example of how a call block can be used with arguments:: + + {% macro dump_users(users) -%} + <ul> + {%- for user in users %} + <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li> + {%- endfor %} + </ul> + {%- endmacro %} + + {% call(user) dump_users(list_of_user) %} + <dl> + <dt>Realname</dt> + <dd>{{ user.realname|e }}</dd> + <dt>Description</dt> + <dd>{{ user.description }}</dd> + </dl> + {% endcall %} + + +Filters +~~~~~~~ + +Filter sections allow you to apply regular Jinja filters on a block of +template data. Just wrap the code in the special `filter` section:: + + {% filter upper %} + This text becomes uppercase + {% endfilter %} + + +.. _assignments: + +Assignments +~~~~~~~~~~~ + +Inside code blocks, you can also assign values to variables. Assignments at +top level (outside of blocks, macros or loops) are exported from the template +like top level macros and can be imported by other templates. + +Assignments use the `set` tag and can have multiple targets:: + + {% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %} + {% set key, value = call_something() %} + +.. admonition:: Scoping Behavior + + Please keep in mind that it is not possible to set variables inside a + block and have them show up outside of it. This also applies to + loops. The only exception to that rule are if statements which do not + introduce a scope. As a result the following template is not going + to do what you might expect:: + + {% set iterated = false %} + {% for item in seq %} + {{ item }} + {% set iterated = true %} + {% endfor %} + {% if not iterated %} did not iterate {% endif %} + + It is not possible with Jinja syntax to do this. Instead use + alternative constructs like the loop else block or the special `loop` + variable:: + + {% for item in seq %} + {{ item }} + {% else %} + did not iterate + {% endfor %} + + As of version 2.10 more complex use cases can be handled using namespace + objects which allow propagating of changes across scopes:: + + {% set ns = namespace(found=false) %} + {% for item in items %} + {% if item.check_something() %} + {% set ns.found = true %} + {% endif %} + * {{ item.title }} + {% endfor %} + Found item having something: {{ ns.found }} + + Note that the ``obj.attr`` notation in the `set` tag is only allowed for + namespace objects; attempting to assign an attribute on any other object + will raise an exception. + + .. versionadded:: 2.10 Added support for namespace objects + + +Block Assignments +~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.8 + +Starting with Jinja 2.8, it's possible to also use block assignments to +capture the contents of a block into a variable name. This can be useful +in some situations as an alternative for macros. In that case, instead of +using an equals sign and a value, you just write the variable name and then +everything until ``{% endset %}`` is captured. + +Example:: + + {% set navigation %} + <li><a href="/">Index</a> + <li><a href="/downloads">Downloads</a> + {% endset %} + +The `navigation` variable then contains the navigation HTML source. + +.. versionchanged:: 2.10 + +Starting with Jinja 2.10, the block assignment supports filters. + +Example:: + + {% set reply | wordwrap %} + You wrote: + {{ message }} + {% endset %} + + +.. _extends: + +Extends +~~~~~~~ + +The `extends` tag can be used to extend one template from another. You can +have multiple `extends` tags in a file, but only one of them may be executed at +a time. + +See the section about :ref:`template-inheritance` above. + + +.. _blocks: + +Blocks +~~~~~~ + +Blocks are used for inheritance and act as both placeholders and replacements +at the same time. They are documented in detail in the +:ref:`template-inheritance` section. + + +Include +~~~~~~~ + +The ``include`` tag renders another template and outputs the result into +the current template. + +.. code-block:: jinja + + {% include 'header.html' %} + Body goes here. + {% include 'footer.html' %} + +The included template has access to context of the current template by +default. Use ``without context`` to use a separate context instead. +``with context`` is also valid, but is the default behavior. See +:ref:`import-visibility`. + +The included template can ``extend`` another template and override +blocks in that template. However, the current template cannot override +any blocks that the included template outputs. + +Use ``ignore missing`` to ignore the statement if the template does not +exist. It must be placed *before* a context visibility statement. + +.. code-block:: jinja + + {% include "sidebar.html" without context %} + {% include "sidebar.html" ignore missing %} + {% include "sidebar.html" ignore missing with context %} + {% include "sidebar.html" ignore missing without context %} + +If a list of templates is given, each will be tried in order until one +is not missing. This can be used with ``ignore missing`` to ignore if +none of the templates exist. + +.. code-block:: jinja + + {% include ['page_detailed.html', 'page.html'] %} + {% include ['special_sidebar.html', 'sidebar.html'] ignore missing %} + +A variable, with either a template name or template object, can also be +passed to the statment. + +.. _import: + +Import +~~~~~~ + +Jinja supports putting often used code into macros. These macros can go into +different templates and get imported from there. This works similarly to the +import statements in Python. It's important to know that imports are cached +and imported templates don't have access to the current template variables, +just the globals by default. For more details about context behavior of +imports and includes, see :ref:`import-visibility`. + +There are two ways to import templates. You can import a complete template +into a variable or request specific macros / exported variables from it. + +Imagine we have a helper module that renders forms (called `forms.html`):: + + {% macro input(name, value='', type='text') -%} + <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}"> + {%- endmacro %} + + {%- macro textarea(name, value='', rows=10, cols=40) -%} + <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols + }}">{{ value|e }}</textarea> + {%- endmacro %} + +The easiest and most flexible way to access a template's variables +and macros is to import the whole template module into a variable. +That way, you can access the attributes:: + + {% import 'forms.html' as forms %} + <dl> + <dt>Username</dt> + <dd>{{ forms.input('username') }}</dd> + <dt>Password</dt> + <dd>{{ forms.input('password', type='password') }}</dd> + </dl> + <p>{{ forms.textarea('comment') }}</p> + + +Alternatively, you can import specific names from a template into the current +namespace:: + + {% from 'forms.html' import input as input_field, textarea %} + <dl> + <dt>Username</dt> + <dd>{{ input_field('username') }}</dd> + <dt>Password</dt> + <dd>{{ input_field('password', type='password') }}</dd> + </dl> + <p>{{ textarea('comment') }}</p> + +Macros and variables starting with one or more underscores are private and +cannot be imported. + +.. versionchanged:: 2.4 + If a template object was passed to the template context, you can + import from that object. + + +.. _import-visibility: + +Import Context Behavior +----------------------- + +By default, included templates are passed the current context and imported +templates are not. The reason for this is that imports, unlike includes, +are cached; as imports are often used just as a module that holds macros. + +This behavior can be changed explicitly: by adding `with context` +or `without context` to the import/include directive, the current context +can be passed to the template and caching is disabled automatically. + +Here are two examples:: + + {% from 'forms.html' import input with context %} + {% include 'header.html' without context %} + +.. admonition:: Note + + In Jinja 2.0, the context that was passed to the included template + did not include variables defined in the template. As a matter of + fact, this did not work:: + + {% for box in boxes %} + {% include "render_box.html" %} + {% endfor %} + + The included template ``render_box.html`` is *not* able to access + `box` in Jinja 2.0. As of Jinja 2.1, ``render_box.html`` *is* able + to do so. + + +.. _expressions: + +Expressions +----------- + +Jinja allows basic expressions everywhere. These work very similarly to +regular Python; even if you're not working with Python +you should feel comfortable with it. + +Literals +~~~~~~~~ + +The simplest form of expressions are literals. Literals are representations +for Python objects such as strings and numbers. The following literals exist: + +``"Hello World"`` + Everything between two double or single quotes is a string. They are + useful whenever you need a string in the template (e.g. as + arguments to function calls and filters, or just to extend or include a + template). + +``42`` / ``123_456`` + Integers are whole numbers without a decimal part. The '_' character + can be used to separate groups for legibility. + +``42.23`` / ``42.1e2`` / ``123_456.789`` + Floating point numbers can be written using a '.' as a decimal mark. + They can also be written in scientific notation with an upper or + lower case 'e' to indicate the exponent part. The '_' character can + be used to separate groups for legibility, but cannot be used in the + exponent part. + +``['list', 'of', 'objects']`` + Everything between two brackets is a list. Lists are useful for storing + sequential data to be iterated over. For example, you can easily + create a list of links using lists and tuples for (and with) a for loop:: + + <ul> + {% for href, caption in [('index.html', 'Index'), ('about.html', 'About'), + ('downloads.html', 'Downloads')] %} + <li><a href="{{ href }}">{{ caption }}</a></li> + {% endfor %} + </ul> + +``('tuple', 'of', 'values')`` + Tuples are like lists that cannot be modified ("immutable"). If a tuple + only has one item, it must be followed by a comma (``('1-tuple',)``). + Tuples are usually used to represent items of two or more elements. + See the list example above for more details. + +``{'dict': 'of', 'key': 'and', 'value': 'pairs'}`` + A dict in Python is a structure that combines keys and values. Keys must + be unique and always have exactly one value. Dicts are rarely used in + templates; they are useful in some rare cases such as the :func:`xmlattr` + filter. + +``true`` / ``false`` + ``true`` is always true and ``false`` is always false. + +.. admonition:: Note + + The special constants `true`, `false`, and `none` are indeed lowercase. + Because that caused confusion in the past, (`True` used to expand + to an undefined variable that was considered false), + all three can now also be written in title case + (`True`, `False`, and `None`). + However, for consistency, (all Jinja identifiers are lowercase) + you should use the lowercase versions. + +Math +~~~~ + +Jinja allows you to calculate with values. This is rarely useful in templates +but exists for completeness' sake. The following operators are supported: + +``+`` + Adds two objects together. Usually the objects are numbers, but if both are + strings or lists, you can concatenate them this way. This, however, is not + the preferred way to concatenate strings! For string concatenation, have + a look-see at the ``~`` operator. ``{{ 1 + 1 }}`` is ``2``. + +``-`` + Subtract the second number from the first one. ``{{ 3 - 2 }}`` is ``1``. + +``/`` + Divide two numbers. The return value will be a floating point number. + ``{{ 1 / 2 }}`` is ``{{ 0.5 }}``. + +``//`` + Divide two numbers and return the truncated integer result. + ``{{ 20 // 7 }}`` is ``2``. + +``%`` + Calculate the remainder of an integer division. ``{{ 11 % 7 }}`` is ``4``. + +``*`` + Multiply the left operand with the right one. ``{{ 2 * 2 }}`` would + return ``4``. This can also be used to repeat a string multiple times. + ``{{ '=' * 80 }}`` would print a bar of 80 equal signs. + +``**`` + Raise the left operand to the power of the right operand. + ``{{ 2**3 }}`` would return ``8``. + + Unlike Python, chained pow is evaluated left to right. + ``{{ 3**3**3 }}`` is evaluated as ``(3**3)**3`` in Jinja, but would + be evaluated as ``3**(3**3)`` in Python. Use parentheses in Jinja + to be explicit about what order you want. It is usually preferable + to do extended math in Python and pass the results to ``render`` + rather than doing it in the template. + + This behavior may be changed in the future to match Python, if it's + possible to introduce an upgrade path. + + +Comparisons +~~~~~~~~~~~ + +``==`` + Compares two objects for equality. + +``!=`` + Compares two objects for inequality. + +``>`` + ``true`` if the left hand side is greater than the right hand side. + +``>=`` + ``true`` if the left hand side is greater or equal to the right hand side. + +``<`` + ``true`` if the left hand side is lower than the right hand side. + +``<=`` + ``true`` if the left hand side is lower or equal to the right hand side. + +Logic +~~~~~ + +For ``if`` statements, ``for`` filtering, and ``if`` expressions, it can be useful to +combine multiple expressions: + +``and`` + Return true if the left and the right operand are true. + +``or`` + Return true if the left or the right operand are true. + +``not`` + negate a statement (see below). + +``(expr)`` + Parentheses group an expression. + +.. admonition:: Note + + The ``is`` and ``in`` operators support negation using an infix notation, + too: ``foo is not bar`` and ``foo not in bar`` instead of ``not foo is bar`` + and ``not foo in bar``. All other expressions require a prefix notation: + ``not (foo and bar).`` + + +Other Operators +~~~~~~~~~~~~~~~ + +The following operators are very useful but don't fit into any of the other +two categories: + +``in`` + Perform a sequence / mapping containment test. Returns true if the left + operand is contained in the right. ``{{ 1 in [1, 2, 3] }}`` would, for + example, return true. + +``is`` + Performs a :ref:`test <tests>`. + +``|`` (pipe, vertical bar) + Applies a :ref:`filter <filters>`. + +``~`` (tilde) + Converts all operands into strings and concatenates them. + + ``{{ "Hello " ~ name ~ "!" }}`` would return (assuming `name` is set + to ``'John'``) ``Hello John!``. + +``()`` + Call a callable: ``{{ post.render() }}``. Inside of the parentheses you + can use positional arguments and keyword arguments like in Python: + + ``{{ post.render(user, full=true) }}``. + +``.`` / ``[]`` + Get an attribute of an object. (See :ref:`variables`) + + +.. _if-expression: + +If Expression +~~~~~~~~~~~~~ + +It is also possible to use inline `if` expressions. These are useful in some +situations. For example, you can use this to extend from one template if a +variable is defined, otherwise from the default layout template:: + + {% extends layout_template if layout_template is defined else 'default.html' %} + +The general syntax is ``<do something> if <something is true> else <do +something else>``. + +The `else` part is optional. If not provided, the else block implicitly +evaluates into an :class:`Undefined` object (regardless of what ``undefined`` +in the environment is set to): + +.. code-block:: jinja + + {{ "[{}]".format(page.title) if page.title }} + + +.. _python-methods: + +Python Methods +~~~~~~~~~~~~~~ + +You can also use any of the methods defined on a variable's type. +The value returned from the method invocation is used as the value of the expression. +Here is an example that uses methods defined on strings (where ``page.title`` is a string): + +.. code-block:: text + + {{ page.title.capitalize() }} + +This works for methods on user-defined types. For example, if variable +``f`` of type ``Foo`` has a method ``bar`` defined on it, you can do the +following: + +.. code-block:: text + + {{ f.bar(value) }} + +Operator methods also work as expected. For example, ``%`` implements +printf-style for strings: + +.. code-block:: text + + {{ "Hello, %s!" % name }} + +Although you should prefer the ``.format`` method for that case (which +is a bit contrived in the context of rendering a template): + +.. code-block:: text + + {{ "Hello, {}!".format(name) }} + + +.. _builtin-filters: + +List of Builtin Filters +----------------------- + +.. py:currentmodule:: jinja-filters + +.. jinja:filters:: jinja2.defaults.DEFAULT_FILTERS + + +.. _builtin-tests: + +List of Builtin Tests +--------------------- + +.. py:currentmodule:: jinja-tests + +.. jinja:tests:: jinja2.defaults.DEFAULT_TESTS + + +.. _builtin-globals: + +List of Global Functions +------------------------ + +The following functions are available in the global scope by default: + +.. py:currentmodule:: jinja-globals + +.. function:: range([start,] stop[, step]) + + Return a list containing an arithmetic progression of integers. + ``range(i, j)`` returns ``[i, i+1, i+2, ..., j-1]``; + start (!) defaults to ``0``. + When step is given, it specifies the increment (or decrement). + For example, ``range(4)`` and ``range(0, 4, 1)`` return ``[0, 1, 2, 3]``. + The end point is omitted! + These are exactly the valid indices for a list of 4 elements. + + This is useful to repeat a template block multiple times, e.g. + to fill a list. Imagine you have 7 users in the list but you want to + render three empty items to enforce a height with CSS:: + + <ul> + {% for user in users %} + <li>{{ user.username }}</li> + {% endfor %} + {% for number in range(10 - users|count) %} + <li class="empty"><span>...</span></li> + {% endfor %} + </ul> + +.. function:: lipsum(n=5, html=True, min=20, max=100) + + Generates some lorem ipsum for the template. By default, five paragraphs + of HTML are generated with each paragraph between 20 and 100 words. + If html is False, regular text is returned. This is useful to generate simple + contents for layout testing. + +.. function:: dict(\**items) + + A convenient alternative to dict literals. ``{'foo': 'bar'}`` is the same + as ``dict(foo='bar')``. + +.. class:: cycler(\*items) + + Cycle through values by yielding them one at a time, then restarting + once the end is reached. + + Similar to ``loop.cycle``, but can be used outside loops or across + multiple loops. For example, render a list of folders and files in a + list, alternating giving them "odd" and "even" classes. + + .. code-block:: html+jinja + + {% set row_class = cycler("odd", "even") %} + <ul class="browser"> + {% for folder in folders %} + <li class="folder {{ row_class.next() }}">{{ folder }} + {% endfor %} + {% for file in files %} + <li class="file {{ row_class.next() }}">{{ file }} + {% endfor %} + </ul> + + :param items: Each positional argument will be yielded in the order + given for each cycle. + + .. versionadded:: 2.1 + + .. method:: current + :property: + + Return the current item. Equivalent to the item that will be + returned next time :meth:`next` is called. + + .. method:: next() + + Return the current item, then advance :attr:`current` to the + next item. + + .. method:: reset() + + Resets the current item to the first item. + +.. class:: joiner(sep=', ') + + A tiny helper that can be used to "join" multiple sections. A joiner is + passed a string and will return that string every time it's called, except + the first time (in which case it returns an empty string). You can + use this to join things:: + + {% set pipe = joiner("|") %} + {% if categories %} {{ pipe() }} + Categories: {{ categories|join(", ") }} + {% endif %} + {% if author %} {{ pipe() }} + Author: {{ author() }} + {% endif %} + {% if can_edit %} {{ pipe() }} + <a href="?action=edit">Edit</a> + {% endif %} + + .. versionadded:: 2.1 + +.. class:: namespace(...) + + Creates a new container that allows attribute assignment using the + ``{% set %}`` tag:: + + {% set ns = namespace() %} + {% set ns.foo = 'bar' %} + + The main purpose of this is to allow carrying a value from within a loop + body to an outer scope. Initial values can be provided as a dict, as + keyword arguments, or both (same behavior as Python's `dict` constructor):: + + {% set ns = namespace(found=false) %} + {% for item in items %} + {% if item.check_something() %} + {% set ns.found = true %} + {% endif %} + * {{ item.title }} + {% endfor %} + Found item having something: {{ ns.found }} + + .. versionadded:: 2.10 + + +Extensions +---------- + +.. py:currentmodule:: jinja2 + +The following sections cover the built-in Jinja extensions that may be +enabled by an application. An application could also provide further +extensions not covered by this documentation; in which case there should +be a separate document explaining said :ref:`extensions +<jinja-extensions>`. + + +.. _i18n-in-templates: + +i18n +~~~~ + +If the :ref:`i18n-extension` is enabled, it's possible to mark text in +the template as translatable. To mark a section as translatable, use a +``trans`` block: + +.. code-block:: jinja + + {% trans %}Hello, {{ user }}!{% endtrans %} + +Inside the block, no statements are allowed, only text and simple +variable tags. + +Variable tags can only be a name, not attribute access, filters, or +other expressions. To use an expression, bind it to a name in the +``trans`` tag for use in the block. + +.. code-block:: jinja + + {% trans user=user.username %}Hello, {{ user }}!{% endtrans %} + +To bind more than one expression, separate each with a comma (``,``). + +.. code-block:: jinja + + {% trans book_title=book.title, author=author.name %} + This is {{ book_title }} by {{ author }} + {% endtrans %} + +To pluralize, specify both the singular and plural forms separated by +the ``pluralize`` tag. + +.. code-block:: jinja + + {% trans count=list|length %} + There is {{ count }} {{ name }} object. + {% pluralize %} + There are {{ count }} {{ name }} objects. + {% endtrans %} + +By default, the first variable in a block is used to determine whether +to use singular or plural form. If that isn't correct, specify the +variable used for pluralizing as a parameter to ``pluralize``. + +.. code-block:: jinja + + {% trans ..., user_count=users|length %}... + {% pluralize user_count %}...{% endtrans %} + +When translating blocks of text, whitespace and linebreaks result in +hard to read and error-prone translation strings. To avoid this, a trans +block can be marked as trimmed, which will replace all linebreaks and +the whitespace surrounding them with a single space and remove leading +and trailing whitespace. + +.. code-block:: jinja + + {% trans trimmed book_title=book.title %} + This is {{ book_title }}. + You should read it! + {% endtrans %} + +This results in ``This is %(book_title)s. You should read it!`` in the +translation file. + +If trimming is enabled globally, the ``notrimmed`` modifier can be used +to disable it for a block. + +.. versionadded:: 2.10 + The ``trimmed`` and ``notrimmed`` modifiers have been added. + +If the translation depends on the context that the message appears in, +the ``pgettext`` and ``npgettext`` functions take a ``context`` string +as the first argument, which is used to select the appropriate +translation. To specify a context with the ``{% trans %}`` tag, provide +a string as the first token after ``trans``. + +.. code-block:: jinja + + {% trans "fruit" %}apple{% endtrans %} + {% trans "fruit" trimmed count -%} + 1 apple + {%- pluralize -%} + {{ count }} apples + {%- endtrans %} + +.. versionadded:: 3.1 + A context can be passed to the ``trans`` tag to use ``pgettext`` and + ``npgettext``. + +It's possible to translate strings in expressions with these functions: + +- ``_(message)``: Alias for ``gettext``. +- ``gettext(message)``: Translate a message. +- ``ngettext(singluar, plural, n)``: Translate a singular or plural + message based on a count variable. +- ``pgettext(context, message)``: Like ``gettext()``, but picks the + translation based on the context string. +- ``npgettext(context, singular, plural, n)``: Like ``npgettext()``, + but picks the translation based on the context string. + +You can print a translated string like this: + +.. code-block:: jinja + + {{ _("Hello, World!") }} + +To use placeholders, use the ``format`` filter. + +.. code-block:: jinja + + {{ _("Hello, %(user)s!")|format(user=user.username) }} + +Always use keyword arguments to ``format``, as other languages may not +use the words in the same order. + +If :ref:`newstyle-gettext` calls are activated, using placeholders is +easier. Formatting is part of the ``gettext`` call instead of using the +``format`` filter. + +.. sourcecode:: jinja + + {{ gettext('Hello World!') }} + {{ gettext('Hello %(name)s!', name='World') }} + {{ ngettext('%(num)d apple', '%(num)d apples', apples|count) }} + +The ``ngettext`` function's format string automatically receives the +count as a ``num`` parameter in addition to the given parameters. + + +Expression Statement +~~~~~~~~~~~~~~~~~~~~ + +If the expression-statement extension is loaded, a tag called `do` is available +that works exactly like the regular variable expression (``{{ ... }}``); except +it doesn't print anything. This can be used to modify lists:: + + {% do navigation.append('a string') %} + + +Loop Controls +~~~~~~~~~~~~~ + +If the application enables the :ref:`loopcontrols-extension`, it's possible to +use `break` and `continue` in loops. When `break` is reached, the loop is +terminated; if `continue` is reached, the processing is stopped and continues +with the next iteration. + +Here's a loop that skips every second item:: + + {% for user in users %} + {%- if loop.index is even %}{% continue %}{% endif %} + ... + {% endfor %} + +Likewise, a loop that stops processing after the 10th iteration:: + + {% for user in users %} + {%- if loop.index >= 10 %}{% break %}{% endif %} + {%- endfor %} + +Note that ``loop.index`` starts with 1, and ``loop.index0`` starts with 0 +(See: :ref:`for-loop`). + + +Debug Statement +~~~~~~~~~~~~~~~ + +If the :ref:`debug-extension` is enabled, a ``{% debug %}`` tag will be +available to dump the current context as well as the available filters +and tests. This is useful to see what's available to use in the template +without setting up a debugger. + +.. code-block:: html+jinja + + <pre>{% debug %}</pre> + +.. code-block:: text + + {'context': {'cycler': <class 'jinja2.utils.Cycler'>, + ..., + 'namespace': <class 'jinja2.utils.Namespace'>}, + 'filters': ['abs', 'attr', 'batch', 'capitalize', 'center', 'count', 'd', + ..., 'urlencode', 'urlize', 'wordcount', 'wordwrap', 'xmlattr'], + 'tests': ['!=', '<', '<=', '==', '>', '>=', 'callable', 'defined', + ..., 'odd', 'sameas', 'sequence', 'string', 'undefined', 'upper']} + + +With Statement +~~~~~~~~~~~~~~ + +.. versionadded:: 2.3 + +The with statement makes it possible to create a new inner scope. +Variables set within this scope are not visible outside of the scope. + +With in a nutshell:: + + {% with %} + {% set foo = 42 %} + {{ foo }} foo is 42 here + {% endwith %} + foo is not visible here any longer + +Because it is common to set variables at the beginning of the scope, +you can do that within the `with` statement. The following two examples +are equivalent:: + + {% with foo = 42 %} + {{ foo }} + {% endwith %} + + {% with %} + {% set foo = 42 %} + {{ foo }} + {% endwith %} + +An important note on scoping here. In Jinja versions before 2.9 the +behavior of referencing one variable to another had some unintended +consequences. In particular one variable could refer to another defined +in the same with block's opening statement. This caused issues with the +cleaned up scoping behavior and has since been improved. In particular +in newer Jinja versions the following code always refers to the variable +`a` from outside the `with` block:: + + {% with a={}, b=a.attribute %}...{% endwith %} + +In earlier Jinja versions the `b` attribute would refer to the results of +the first attribute. If you depend on this behavior you can rewrite it to +use the ``set`` tag:: + + {% with a={} %} + {% set b = a.attribute %} + {% endwith %} + +.. admonition:: Extension + + In older versions of Jinja (before 2.9) it was required to enable this + feature with an extension. It's now enabled by default. + +.. _autoescape-overrides: + +Autoescape Overrides +-------------------- + +.. versionadded:: 2.4 + +If you want you can activate and deactivate the autoescaping from within +the templates. + +Example:: + + {% autoescape true %} + Autoescaping is active within this block + {% endautoescape %} + + {% autoescape false %} + Autoescaping is inactive within this block + {% endautoescape %} + +After an `endautoescape` the behavior is reverted to what it was before. + +.. admonition:: Extension + + In older versions of Jinja (before 2.9) it was required to enable this + feature with an extension. It's now enabled by default. diff --git a/docs/tricks.rst b/docs/tricks.rst new file mode 100644 index 0000000..b58c5bb --- /dev/null +++ b/docs/tricks.rst @@ -0,0 +1,100 @@ +Tips and Tricks +=============== + +.. highlight:: html+jinja + +This part of the documentation shows some tips and tricks for Jinja +templates. + + +.. _null-default-fallback: + +Null-Default Fallback +--------------------- + +Jinja supports dynamic inheritance and does not distinguish between parent +and child template as long as no `extends` tag is visited. While this leads +to the surprising behavior that everything before the first `extends` tag +including whitespace is printed out instead of being ignored, it can be used +for a neat trick. + +Usually child templates extend from one template that adds a basic HTML +skeleton. However it's possible to put the `extends` tag into an `if` tag to +only extend from the layout template if the `standalone` variable evaluates +to false which it does per default if it's not defined. Additionally a very +basic skeleton is added to the file so that if it's indeed rendered with +`standalone` set to `True` a very basic HTML skeleton is added:: + + {% if not standalone %}{% extends 'default.html' %}{% endif -%} + <!DOCTYPE html> + <title>{% block title %}The Page Title{% endblock %}</title> + <link rel="stylesheet" href="style.css" type="text/css"> + {% block body %} + <p>This is the page body.</p> + {% endblock %} + + +Alternating Rows +---------------- + +If you want to have different styles for each row of a table or +list you can use the `cycle` method on the `loop` object:: + + <ul> + {% for row in rows %} + <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li> + {% endfor %} + </ul> + +`cycle` can take an unlimited number of strings. Each time this +tag is encountered the next item from the list is rendered. + + +Highlighting Active Menu Items +------------------------------ + +Often you want to have a navigation bar with an active navigation +item. This is really simple to achieve. Because assignments outside +of `block`\s in child templates are global and executed before the layout +template is evaluated it's possible to define the active menu item in the +child template:: + + {% extends "layout.html" %} + {% set active_page = "index" %} + +The layout template can then access `active_page`. Additionally it makes +sense to define a default for that variable:: + + {% set navigation_bar = [ + ('/', 'index', 'Index'), + ('/downloads/', 'downloads', 'Downloads'), + ('/about/', 'about', 'About') + ] -%} + {% set active_page = active_page|default('index') -%} + ... + <ul id="navigation"> + {% for href, id, caption in navigation_bar %} + <li{% if id == active_page %} class="active"{% endif %}> + <a href="{{ href|e }}">{{ caption|e }}</a></li> + {% endfor %} + </ul> + ... + +.. _accessing-the-parent-loop: + +Accessing the parent Loop +------------------------- + +The special `loop` variable always points to the innermost loop. If it's +desired to have access to an outer loop it's possible to alias it:: + + <table> + {% for row in table %} + <tr> + {% set rowloop = loop %} + {% for cell in row %} + <td id="cell-{{ rowloop.index }}-{{ loop.index }}">{{ cell }}</td> + {% endfor %} + </tr> + {% endfor %} + </table> |