Skip to content

Commit

Permalink
documentation update
Browse files Browse the repository at this point in the history
--HG--
branch : trunk
  • Loading branch information
mitsuhiko committed May 7, 2008
1 parent ed98cac commit 5cdc1ac
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 34 deletions.
7 changes: 6 additions & 1 deletion docs/_static/style.css
Expand Up @@ -196,6 +196,10 @@ tt {
border-bottom: 1px solid #eee;
}

a.reference:hover tt {
border-bottom-color: #aaa;
}

cite {
/* abusing <cite>, it's generated by ReST for `x` */
font-size: 13px;
Expand Down Expand Up @@ -291,7 +295,8 @@ table.indextable dl dd a {
}

dl.function dt,
dl.class dt {
dl.class dt,
dl.exception dt {
font-weight: normal;
}

Expand Down
14 changes: 8 additions & 6 deletions docs/api.rst
Expand Up @@ -48,7 +48,7 @@ High Level API
--------------

.. autoclass:: jinja2.environment.Environment([options])
:members: from_string, get_template, join_path, parse
:members: from_string, get_template, join_path, parse, lex

.. attribute:: shared

Expand Down Expand Up @@ -174,6 +174,8 @@ The Context
block (latest in the inheritance chain).


.. _loaders:

Loaders
-------

Expand Down Expand Up @@ -232,15 +234,15 @@ functions to a Jinja2 environment.
Exceptions
----------

.. autoclass:: jinja2.exceptions.TemplateError
.. autoexception:: jinja2.exceptions.TemplateError

.. autoclass:: jinja2.exceptions.UndefinedError
.. autoexception:: jinja2.exceptions.UndefinedError

.. autoclass:: jinja2.exceptions.TemplateNotFound
.. autoexception:: jinja2.exceptions.TemplateNotFound

.. autoclass:: jinja2.exceptions.TemplateSyntaxError
.. autoexception:: jinja2.exceptions.TemplateSyntaxError

.. autoclass:: jinja2.exceptions.TemplateAssertionError
.. autoexception:: jinja2.exceptions.TemplateAssertionError


.. _writing-filters:
Expand Down
2 changes: 2 additions & 0 deletions docs/index.rst
Expand Up @@ -10,9 +10,11 @@ fast and secure.

intro
api
sandbox
templates
extensions
integration
switching

changelog

Expand Down
27 changes: 27 additions & 0 deletions docs/sandbox.rst
@@ -0,0 +1,27 @@
Sandbox
=======

The Jinja2 sandbox can be used to evaluate untrusted code. Access to unsafe
attributes and methods is prohibited.

Assuming `env` is a :class:`SandboxedEnvironment` in the default configuration
the following piece of code shows how it works:

>>> env.from_string("{{ func.func_code }}").render(func=lambda:None)
u''
>>> env.from_string("{{ func.func_code.do_something }}").render(func=lambda:None)
Traceback (most recent call last):
...
SecurityError: access to attribute 'func_code' of 'function' object is unsafe.


.. module:: jinja2.sandbox

.. autoclass:: SandboxedEnvironment([options])
:members: is_safe_attribute, is_safe_callable

.. autoexception:: SecurityError

.. autofunction:: unsafe

.. autofunction:: is_internal_attribute
217 changes: 217 additions & 0 deletions docs/switching.rst
@@ -0,0 +1,217 @@
Switching from other Template Engines
=====================================

.. highlight:: html+jinja

If you have used a different template engine in the past and want to swtich
to Jinja2 here is a small guide that shows the basic syntatic and semantic
changes between some common, similar text template engines for Python.

Jinja1
------

Jinja2 is mostly compatible with Jinja1 in terms of API usage and template
syntax. The differences between Jinja1 and 2 are explained in the following
list.

API
~~~

Loaders
Jinja2 uses a different loader API. Because the internal representation
of templates changed there is no longer support for external caching
systems such as memcached. The memory consumed by templates is comparable
with regular Python modules now and external caching doesn't give any
advantage. If you have used a custom loader in the past have a look at
the new :ref:`loader API <loaders>`.

Loading templates from strings
In the past it was possible to generate templates from a string with the
default environment configuration by using `jinja.from_string`. Jinja2
provides a :class:`Template` class that can be used to do the same, but
with optional additional configuration.

Automatic unicode conversion
Jinja1 performed automatic conversion of bytestrings in a given encoding
into unicode objects. This conversion is no longer implemented as it
was inconsistent as most libraries are using the regular Python ASCII
bytestring to Unicode conversion. An application powered by Jinja2
*has to* use unicode internally everywhere or make sure that Jinja2 only
gets unicode strings passed.

i18n
Jinja1 used custom translators for internationalization. i18n is now
available as Jinja2 extension and uses a simpler, more gettext friendly
interface and has support for babel. For more details see
:ref:`i18n-extension`.

Internal methods
Jinja1 exposed a few internal methods on the environment object such
as `call_function`, `get_attribute` and others. While they were marked
as being an internal method it was possible to override them. Jinja2
doesn't have equivalent methods.

Sandbox
Jinja1 was running sandbox mode by default. Few applications actually
used that feature so it became optional in Jinja2. For more details
about the sandboxed execution see :class:`SandboxedEnvironment`.

Context
Jinja1 had a stacked context as storage for variables passed to the
environment. In Jinja2 a similar object exists but it doesn't allow
modifications nor is it a singleton. As inheritance is dynamic now
multiple context objects may exist during template evaluation.


Templates
~~~~~~~~~

Jinja2 has mostly the same syntax as Jinja1. The only difference is that
assigning variables doesn't use `set` as keyword now. The following
example shows a Jinja1 variable assignment::

{% set foo = 42 %}

In Jinja2 the `set` is ommited::

{% foo = 42 %}

Additionally macros require parentheses around the argument list now.

Jinja2 allows dynamic inheritance now and dynamic includes. The old helper
function `rendertemplate` is gone now, `include` can be used instead.
Additionally includes no longer import macros and variable assignments, for
that the new `import` tag is used. This concept is explained in the
:ref:`import` documentation.

Currently there is no support for the `recursive` modifier of for loops!


Django
------

If you have previously worked with Django templates, you should find
Jinja2 very familiar. In fact, most of the syntax elements look and
work the same.

However, Jinja2 provides some more syntax elements covered in the
documentation and some work a bit different.

This section covers the template changes. As the API is fundamentally
different we won't cover it here.

Method Calls
~~~~~~~~~~~~

In Django method calls work implicitly. With Jinja2 you have to specify that
you want to call an object. Thus this Django code::

{% for page in user.get_created_pages %}
...
{% endfor %}
will look like this in Jinja::

{% for page in user.get_created_pages() %}
...
{% endfor %}

This allows you to pass variables to the function which is also used for macros
which is not possible in Django.

Conditions
~~~~~~~~~~

In Django you can use the following constructs to check for equality::

{% ifequals foo "bar" %}
...
{% else %}
...
{% endifequals %}

In Jinja2 you can use the normal if statement in combination with operators::

{% if foo == 'bar' %}
...
{% else %}
...
{% endif %}

You can also have multiple elif branches in your template::

{% if something %}
...
{% elif otherthing %}
...
{% elif foothing %}
...
{% else %}
...
{% endif %}

Filter Arguments
~~~~~~~~~~~~~~~~

Jinja2 provides more than one argument for filters. Also the syntax for
argument passing is different. A template that looks like this in Django::

{{ items|join:", " }}

looks like this in Jinja2::

{{ items|join(', ') }}

In fact it's a bit more verbose but it allows different types of arguments -
including variables - and more than one of them.

Tests
~~~~~

In addition to filters there also are tests you can perform using the is
operator. Here are some examples::

{% if user.user_id is odd %}
{{ user.username|e }} is odd
{% else %}
hmm. {{ user.username|e }} looks pretty normal
{% endif %}


Mako
----

.. highlight:: html+mako

If you have used Mako so far and want to switch to Jinja2 you can configure
Jinja2 to look more like Mako:

.. sourcecode:: python

env = Environment('<%', '%>', '${', '}', '%')

Once the environment is configure like that Jinja2 should be able to interpret
a small subset of Mako templates. Jinja2 does not support embedded Python code
so you would have to move that out of the template. The syntax for defs (in
Jinja2 defs are called macros) and template inheritance is different too. The
following Mako template::

<%inherit file="layout.html" />
<%def name="title()">Page Title</%def>
<ul>
% for item in list:
<li>${item}</li>
% endfor
</ul>

Looks like this in Jinja2 with the above configuration::

<% extends "layout.html" %>
<% block title %>Page Title<% endblock %>
<% block body %>
<ul>
% for item in list:
<li>${item}</li>
% endfor
</ul>
<% endblock %>
6 changes: 4 additions & 2 deletions jinja2/environment.py
Expand Up @@ -293,11 +293,13 @@ def parse(self, source, filename=None):
exc_type, exc_value, tb = translate_syntax_error(e)
raise exc_type, exc_value, tb

def lex(self, source, name=None):
def lex(self, source, filename=None):
"""Lex the given sourcecode and return a generator that yields
tokens as tuples in the form ``(lineno, token_type, value)``.
This can be useful for :ref:`extension development <writing-extensions>`
and debugging templates.
"""
return self.lexer.tokeniter(source, name)
return self.lexer.tokeniter(source, filename)

def compile(self, source, name=None, filename=None, globals=None,
raw=False):
Expand Down
6 changes: 6 additions & 0 deletions jinja2/exceptions.py
Expand Up @@ -18,6 +18,12 @@ class UndefinedError(TemplateError):
"""Raised if a template tries to operate on :class:`Undefined`."""


class SecurityError(TemplateError):
"""Raised if a template tries to do something insecure if the
sandbox is enabled.
"""


class TemplateNotFound(IOError, LookupError, TemplateError):
"""Raised if a template does not exist."""

Expand Down
8 changes: 5 additions & 3 deletions jinja2/runtime.py
Expand Up @@ -306,7 +306,7 @@ def fail_with_undefined_error(self, *args, **kwargs):
)
else:
hint = self._undefined_hint
raise UndefinedError(hint)
raise self._undefined_exception(hint)


class Undefined(object):
Expand All @@ -323,12 +323,14 @@ class Undefined(object):
...
jinja2.exceptions.UndefinedError: 'foo' is undefined
"""
__slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name')
__slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
'_undefined_exception')

def __init__(self, hint=None, obj=None, name=None):
def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
self._undefined_hint = hint
self._undefined_obj = obj
self._undefined_name = name
self._undefined_exception = exc

__add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
__realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
Expand Down

0 comments on commit 5cdc1ac

Please sign in to comment.