Framework Integration
=====================
-Jinja registers itself in the buffet template plugin system. If your framework
-supports buffet (currently `TurboGears`_ and `pylons`_) you can add it very
-easily.
-
-Pylons
-------
-
-Edit ``yourproject/config/middleware.py`` and add the following lines to
-`config.init_app...`:
-
-.. sourcecode:: python
-
- from jinja import Environment, FileSystemLoader
-
- config.add_template_engine('jinja', {
- 'jinja.environment': Environment(loader=FileSystemLoader('path/to/templates'))
- })
-
-To make Jinja the default template engine change the `init_app` call to
-something like this:
-
-.. sourcecode:: python
-
- config.init_app(global_conf, app_conf, package='yourproject',
- template_engine='jinja')
-
-If you load templates using dotted notation the ``'.html'`` to the filename.
-You can override this using ``jinja.exception``. eg:
-
-.. sourcecode:: python
-
- config.add_template_engine('jinja', {
- 'jinja.environment': ...,
- 'jinja.extension': 'tmpl'
- })
-
-Note that you have to use a trailing slash to load templates if you want to
-specify the extension. Otherwise use the dotted notation:
-
-.. sourcecode:: python
-
- render_template('/index.html')
- render_template('index')
-
- render_template('/modules/userlist.html')
- render_template('modules.userlist')
-
-
-TurboGears
-----------
-
-The TurboGears template plugin interface is broken by design and
-there is currently no way to embed Jinja templates in TurboGears.
-
-
-.. _TurboGears: http://www.turbogears.org/
-.. _pylons: http://www.pylonshq.com/
+Because the buffet template interface does not support more complex usage
+cases there is currently no built in framework support. This however will
+hopefully change before the Jinja release.
def do_truncate(s, length=255, killwords=False, end='...'):
"""
- {{ s|truncate[ length[ killwords[ end]]] }}
-
Return a truncated copy of the string. The length is specified
with the first parameter which defaults to ``255``. If the second
parameter is ``true`` the filter will cut the text at length. Otherwise
from jinja.datastructure import TokenStream
from jinja.exceptions import TemplateSyntaxError
+try:
+ set
+except NameError:
+ from sets import Set as set
+
# static regular expressions
whitespace_re = re.compile(r'\s+(?m)')
ur'or\b', ur'and\b', ur'not\b', ur'in\b', ur'is'
]))
+# set of names that are keywords in python but not in jinja. the lexer
+# appends three trailing underscores, the parser removes them again later
+escaped_names = set(['with', 'as', 'import', 'from', 'class', 'def',
+ 'try', 'except', 'exec', 'global', 'assert',
+ 'break', 'continue', 'lambda', 'return', 'raise',
+ 'yield', 'while', 'pass', 'finally'])
+
class Failure(object):
"""
tuples. Wrap the generator returned by this function in a
`TokenStream` to get real token instances and be able to push tokens
back to the stream. That's for example done by the parser.
+
+ Additionally some names like "class" are escaped
"""
- return TokenStream(self.tokeniter(source))
+ def filter():
+ for lineno, token, value in self.tokeniter(source):
+ if token == 'name' and value in escaped_names:
+ value += '___'
+ yield lineno, token, value
+ return TokenStream(filter())
def tokeniter(self, source):
"""
self.package_path = package_path
# if we have an loader we probably retrieved it from an egg
# file. In that case don't use the auto_reload!
- if auto_reload:
- package = __import__(package_name, '', '', [''])
- if package.__loader__ is not None:
- auto_reload = False
+ if auto_reload and getattr(__import__(package_name, '', '', ['']),
+ '__loader__', None) is not None:
+ auto_reload = False
CachedLoaderMixin.__init__(self, use_memcache, memcache_size,
cache_folder, auto_reload)
def get_source(self, environment, name, parent):
name = '/'.join([self.package_path] + [p for p in name.split('/')
- if p and p[0] != '.'])
- if not resource_exists(self.package, name):
+ if p != '..'])
+ if not resource_exists(self.package_name, name):
raise TemplateNotFound(name)
contents = resource_string(self.package_name, name)
return contents.decode(environment.template_charset)
def check_source_changed(self, environment, name):
name = '/'.join([self.package_path] + [p for p in name.split('/')
if p and p[0] != '.'])
- return path.getmtime(resource_filename(name))
+ return path.getmtime(resource_filename(self.package_name, name))
class DictLoader(BaseLoader):
:license: BSD, see LICENSE for more details.
"""
from compiler import ast
-from compiler.misc import set_filename
def inc_lineno(offset, tree):
body = (body,)
NodeList.__init__(self, 1, body)
self.extends = extends
- set_filename(filename, self)
+ self.filename = filename
def get_items(self):
if self.extends is not None:
from compiler import ast, parse
from compiler.misc import set_filename
from jinja import nodes
+from jinja.lexer import escaped_names
from jinja.datastructure import TokenStream
from jinja.exceptions import TemplateSyntaxError
try:
def parse(self):
"""
- Parse the template and return a Template node.
+ Parse the template and return a Template node. Also unescape the
+ names escaped by the lexer (unused python keywords) and set the
+ filename attributes for all nodes in the tree.
"""
body = self.subparse(None)
+ todo = [body]
+ while todo:
+ node = todo.pop()
+ if node.__class__ in (ast.AssName, ast.Name) and \
+ node.name.endswith('___') and node.name[:-3] in escaped_names:
+ node.name = node.name[:-3]
+ node.filename = self.filename
+ todo.extend(node.getChildNodes())
return nodes.Template(self.filename, body, self.extends)
def subparse(self, test, drop_needle=False):
+++ /dev/null
-# -*- coding: utf-8 -*-
-"""
- jinja.plugin
- ~~~~~~~~~~~~
-
- This module proides a bridge to buffed so that you can use Jinja
- in pylons. Note that this doesn't work with turbogears because their
- buffet implementation is broken.
-
- :copyright: 2007 by Armin Ronacher.
- :license: BSD, see LICENSE for more details.
-"""
-
-from jinja import Environment
-
-
-class ConfigurationError(ValueError):
- """
- Raised if an configuration error occoured.
- """
-
-
-class JinjaPlugin(object):
- """
- Implementation of the Plugin API
- """
- extension = 'html'
-
- def __init__(self, extra_vars_func=None, options=None):
- self.get_extra_vars = extra_vars_func
- options = options or {}
- if 'jinja.environment' in options:
- self.environment = options['jinja.environment']
- elif 'jinja.init_callback' in options:
- name = options['jinja.init_callback']
- p = name.rsplit('.', 1)
- func = getattr(__import__(p[0], '', '', ['']), p[1])
- self.environment = func(options)
- else:
- raise ConfigurationError('no jinja environment defined')
- if 'jinja.extension' in options:
- self.extension = options['jinja.extension']
-
- def load_template(self, templatename, template_string=None):
- """
- Find a template specified in python 'dot' notation, or load one from
- a string.
- """
- if template_string is not None:
- return self.environment.from_string(template_string)
-
- # Translate TG dot notation to normal / template path
- if templatename.startswith('/'):
- templatename = templatename[1:]
- else:
- templatename = templatename.replace('.', '/') + '.' + self.extension
-
- return self.environment.get_template(templatename)
-
- def render(self, info, format='html', fragment=False, template=None):
- """
- Render a template.
- """
- if isinstance(template, basestring):
- template = self.load_template(template)
-
- if self.get_extra_vars:
- info.update(self.get_extra_vars())
-
- return template.render(**info)
],
keywords = ['python.templating.engines'],
packages = ['jinja', 'jinja.translators'],
- extras_require = {'plugin': ['setuptools>=0.6a2']},
- entry_points='''
- [python.templating.engines]
- jinja = jinja.plugin:JinjaPlugin[plugin]
- '''
+ extras_require = {'plugin': ['setuptools>=0.6a2']}
)