For more details about unicode in Python have a look at the excellent
`Unicode documentation`_.
+Another important thing is how Jinja2 is handling string literals in
+templates. A naive implementation would be using unicode strings for
+all string literals but it turned out in the past that this is problematic
+as some libraries are typechecking against `str` explicitly. For example
+`datetime.strftime` does not accept unicode arguments. To not break it
+completely Jinja2 is returning `str` for strings that fit into ASCII and
+for everything else `unicode`:
+
+>>> m = Template(u"{% set a, b = 'foo', 'föö' %}").module
+>>> m.a
+'foo'
+>>> m.b
+u'f\xf6\xf6'
+
.. _Unicode documentation: http://docs.python.org/dev/howto/unicode.html
.. automethod:: overlay([options])
- .. method:: undefined([hint,] [obj,] name[, exc])
+ .. 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
return 0.0
To disallow a method, just override it and raise
- :attr:`_undefined_exception`. Because this is a very common idom in
- undefined objects there is the helper method
- :meth:`_fail_with_undefined_error`. That does that automatically. Here
- a class that works like the regular :class:`UndefinedError` but chokes
- on iteration::
+ :attr:`~Undefined._undefined_exception`. Because this is a very common
+ idom in undefined objects there is the helper method
+ :meth:`~Undefined._fail_with_undefined_error` that does the error raising
+ automatically. Here a class that works like the regular :class:`Undefined`
+ but chokes on iteration::
class NonIterableUndefined(Undefined):
__iter__ = Undefined._fail_with_undefined_error
.. autofunction:: jinja2.utils.is_undefined
-.. autoclass:: jinja2.utils.Markup
+.. autoclass:: jinja2.utils.Markup([string])
+ :members: escape, unescape, striptags
+
+.. admonition:: Note
+
+ The Jinja2 :class:`Markup` class is compatible with at least Pylons and
+ Genshi. It's expected that more template engines and framework will pick
+ up the `__html__` concept soon.
Exceptions
.. admonition:: Note
- The low-level API is fragile. Future Jinja2 versions will not change it
- in a backwards incompatible way but modifications in the Jinja core may
- shine through. For example if Jinja2 introduces a new AST node in later
- versions that may be returned by :meth:`~Environment.parse`.
+ The low-level API is fragile. Future Jinja2 versions will try not to
+ change it in a backwards incompatible way but modifications in the Jinja2
+ core may shine through. For example if Jinja2 introduces a new AST node
+ in later versions that may be returned by :meth:`~Environment.parse`.
or (path.altsep and path.altsep in piece) or \
piece == path.pardir:
raise TemplateNotFound(template)
- elif piece != '.':
+ elif piece and piece != '.':
pieces.append(piece)
return pieces
a function that returns a sorted list of template variables the current
template exports could look like this::
- @contextcallable
+ @contextfunction
def get_exported_names(context):
return sorted(context.exported_vars)
"""
class Markup(unicode):
- """Marks a string as being safe for inclusion in HTML/XML output without
+ r"""Marks a string as being safe for inclusion in HTML/XML output without
needing to be escaped. This implements the `__html__` interface a couple
- of frameworks and web applications use.
+ of frameworks and web applications use. :class:`Markup` is a direct
+ subclass of `unicode` and provides all the methods of `unicode` just that
+ it escapes arguments passed and always returns `Markup`.
The `escape` function returns markup objects so that double escaping can't
happen. If you want to use autoescaping in Jinja just set the finalizer
of the environment to `escape`.
+
+ The constructor of the :class:`Markup` class can be used for three
+ different things: When passed an unicode object it's assumed to be safe,
+ when passed an object with an HTML representation (has an `__html__`
+ method) that representation is used, otherwise the object passed is
+ converted into a unicode string and then assumed to be safe:
+
+ >>> Markup("Hello <em>World</em>!")
+ Markup(u'Hello <em>World</em>!')
+ >>> class Foo(object):
+ ... def __html__(self):
+ ... return '<a href="#">foo</a>'
+ ...
+ >>> Markup(Foo())
+ Markup(u'<a href="#">foo</a>')
+
+ If you want object passed being always treated as unsafe you can use the
+ :meth:`escape` classmethod to create a :class:`Markup` object:
+
+ >>> Markup.escape("Hello <em>World</em>!")
+ Markup(u'Hello <em>World</em>!')
+
+ Operations on a markup string are markup aware which means that all
+ arguments are passed through the :func:`escape` function:
+
+ >>> em = Markup("<em>%s</em>")
+ >>> em % "foo & bar"
+ Markup(u'<em>foo & bar</em>')
+ >>> strong = Markup("<strong>%(text)s</strong>")
+ >>> strong % {'text': '<blink>hacker here</blink>'}
+ Markup(u'<strong><blink>hacker here</blink></strong>')
+ >>> Markup("<em>Hello</em> ") + "<foo>"
+ Markup(u'<em>Hello</em> <foo>')
"""
__slots__ = ()
splitlines.__doc__ = unicode.splitlines.__doc__
def unescape(self):
- """Unescape markup."""
+ r"""Unescape markup again into an unicode string. This also resolves
+ known HTML4 and XHTML entities:
+
+ >>> Markup("Main » <em>About</em>").unescape()
+ u'Main \xbb <em>About</em>'
+ """
def handle_match(m):
name = m.group(1)
if name in _entities:
return _entity_re.sub(handle_match, unicode(self))
def striptags(self):
- """Strip tags and resolve enities."""
+ r"""Unescape markup into an unicode string and strip all tags. This
+ also resolves known HTML4 and XHTML entities. Whitespace is
+ normalized to one:
+
+ >>> Markup("Main » <em>About</em>").striptags()
+ u'Main \xbb About'
+ """
stripped = u' '.join(_striptags_re.sub('', self).split())
return Markup(stripped).unescape()
@classmethod
def escape(cls, s):
- """Escape the string. Works like :func:`escape`."""
+ """Escape the string. Works like :func:`escape` with the difference
+ that for subclasses of :class:`Markup` this function would return the
+ correct subclass.
+ """
rv = escape(s)
if rv.__class__ is not cls:
return cls(rv)
class LRUCache(object):
"""A simple LRU Cache implementation."""
- # this is fast for small capacities (something around 200) but doesn't
- # scale. But as long as it's only used for the database connections in
- # a non request fallback it's fine.
+
+ # this is fast for small capacities (something below 1000) but doesn't
+ # scale. But as long as it's only used as storage for templates this
+ # won't do any harm.
def __init__(self, capacity):
self.capacity = capacity
from distutils.errors import CCompilerError, DistutilsPlatformError
-def list_files(path):
- for fn in os.listdir(path):
- if fn.startswith('.'):
- continue
- fn = os.path.join(path, fn)
- if os.path.isfile(fn):
- yield fn
+data_files = []
+documentation_path = 'docs/_build/html'
+if os.path.exists(documentation_path):
+ documentation_files = []
+ for fn in os.listdir(documentation_path):
+ if not fn.startswith('.'):
+ fn = os.path.join(documentation_path, fn)
+ if os.path.isfile(fn):
+ documentation_files.append(fn)
+ data_files.append(('docs', documentation_files))
def get_terminal_width():
print """WARNING:
An optional C extension could not be compiled, speedups will not be
available."""
- print '*' * width
setup(
'Topic :: Text Processing :: Markup :: HTML'
],
packages=['jinja2'],
- data_files=[
- ('docs', list(list_files('docs/_build/html')))
- ],
+ data_files=data_files,
features={
'speedups': Feature("optional C speed-enhancements",
standard=True,