Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

data files are optional now

--HG--
branch : trunk
  • Loading branch information...
commit 58f351da2c71873e5c41b98a871ac1af78624f65 1 parent 9ddd0b8
@mitsuhiko authored
Showing with 103 additions and 32 deletions.
  1. +32 −11 docs/api.rst
  2. +1 −1  jinja2/loaders.py
  3. +59 −9 jinja2/utils.py
  4. +11 −11 setup.py
View
43 docs/api.rst
@@ -89,6 +89,20 @@ unicode string.
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
@@ -140,7 +154,7 @@ useful if you want to dig deeper into Jinja2 or :ref:`develop extensions
.. 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
@@ -285,11 +299,11 @@ Undefined objects are created by calling :attr:`undefined`.
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
@@ -410,7 +424,14 @@ functions to a Jinja2 environment.
.. 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
@@ -596,7 +617,7 @@ don't recommend using any of those.
.. 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`.
View
2  jinja2/loaders.py
@@ -23,7 +23,7 @@ def split_template_path(template):
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
View
68 jinja2/utils.py
@@ -70,7 +70,7 @@ def contextfunction(f):
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)
"""
@@ -248,13 +248,48 @@ def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
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 &lt;em&gt;World&lt;/em&gt;!')
+
+ 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 &amp; bar</em>')
+ >>> strong = Markup("<strong>%(text)s</strong>")
+ >>> strong % {'text': '<blink>hacker here</blink>'}
+ Markup(u'<strong>&lt;blink&gt;hacker here&lt;/blink&gt;</strong>')
+ >>> Markup("<em>Hello</em> ") + "<foo>"
+ Markup(u'<em>Hello</em> &lt;foo&gt;')
"""
__slots__ = ()
@@ -312,7 +347,12 @@ def splitlines(self, *args, **kwargs):
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 &raquo; <em>About</em>").unescape()
+ u'Main \xbb <em>About</em>'
+ """
def handle_match(m):
name = m.group(1)
if name in _entities:
@@ -328,13 +368,22 @@ def handle_match(m):
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 &raquo; <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)
@@ -392,9 +441,10 @@ def __init__(self, obj):
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
View
22 setup.py
@@ -49,13 +49,16 @@
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():
@@ -91,7 +94,6 @@ def _unavailable(self):
print """WARNING:
An optional C extension could not be compiled, speedups will not be
available."""
- print '*' * width
setup(
@@ -119,9 +121,7 @@ def _unavailable(self):
'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,
Please sign in to comment.
Something went wrong with that request. Please try again.