[svn] added a sanity check for block tags outside the root level
[jinja2.git] / jinja / plugin.py
1 # -*- coding: utf-8 -*-
2 """
3     jinja.plugin
4     ~~~~~~~~~~~~
5
6     Support for the `GeneralTemplateInterface`__ and the Buffet interface.
7
8     Do not use this module on your own. We don't recommend those interfaces!
9     If you are able to, you should really use Jinja without those abstraction
10     layers.
11
12     __ http://trac.pocoo.org/wiki/GeneralTemplateInterface
13
14     :copyright: 2007 by Armin Ronacher.
15     :license: BSD, see LICENSE for more details.
16 """
17 from jinja.environment import Environment
18 from jinja.loaders import FunctionLoader, FileSystemLoader, PackageLoader
19 from jinja.exceptions import TemplateNotFound
20
21
22 class BuffetPlugin(object):
23     """
24     Implements the Jinja buffet plugin. Well. It works for pylons and should
25     work for TurboGears too if their plugin system would work.
26     """
27
28     def __init__(self, extra_vars_func=None, options=None):
29         if 'jinja.environment' in options:
30             self.env = options['jinja.environment']
31         else:
32             opt = {}
33             for key, value in options.iteritems():
34                 if key.startswith('jinja.') and key != 'jinja.extension':
35                     opt[key[6:]] = value
36             loader_func = opt.pop('loader_func', None)
37             getmtime_func = opt.pop('getmtime_func', None)
38             use_memcache = opt.pop('use_memcache', False)
39             memcache_size = opt.pop('memcache_size', 40)
40             cache_folder = opt.pop('cache_folder', None)
41             auto_reload = opt.pop('auto_reload', True)
42             if 'searchpath' in options:
43                 opt['loader'] = FileSystemLoader(opt.pop('searchpath'),
44                                                  use_memcache, memcache_size,
45                                                  cache_folder, auto_reload)
46             elif 'package' in options:
47                 opt['loader'] = PackageLoader(opt.pop('package'),
48                                               opt.pop('package_path', ''),
49                                               use_memcache, memcache_size,
50                                               cache_folder, auto_reload)
51             elif loader_func is not None:
52                 opt['loader'] = FunctionLoader(loader_func, getmtime_func,
53                                                use_memcache, memcache_size,
54                                                cache_folder, auto_reload)
55             self.env = Environment(**opt)
56
57         self.extra_vars_func = extra_vars_func
58         self.extension = options.pop('jinja.extension', 'html')
59
60     def load_template(self, templatename, template_string=None):
61         if template_string is not None:
62             return self.env.from_string(template_string)
63         if templatename.startswith('!'):
64             jinja_name = templatename[1:]
65         else:
66             jinja_name = templatename.replace('.', '/') + '.' + self.extension
67         return self.env.get_template(jinja_name)
68
69     def render(self, info, format='html', fragment=False, template=None):
70         if isinstance(template, basestring):
71             template = self.load_template(template)
72         if self.extra_vars_func:
73             info.update(self.extra_vars_func())
74         return template.render(info)
75
76
77 def jinja_plugin_factory(options):
78     """
79     Basic implementation of the `GeneralTemplateInterface`.
80
81     Supports ``loader_func`` and ``getmtime_func``, as well as
82     string and file loading but ignores ``mode`` since it's a
83     text based template engine.
84
85     All options passed to this function are forwarded to the
86     jinja environment. Exceptions are the following keys:
87
88     =================== =================================================
89     ``environment``     If this is provided it must be the only
90                         configuration value and it's used as jinja
91                         environment.
92     ``searchpath``      If provided a new file system loader with this
93                         search path is instanciated.
94     ``package``         Name of the python package containing the
95                         templates. If this and ``package_path`` is
96                         defined a `PackageLoader` is used.
97     ``package_path``    Path to the templates inside of a package.
98     ``loader_func``     Function that takes the name of the template to
99                         load. If it returns a string or unicode object
100                         it's used to load a template. If the return
101                         value is None it's considered missing.
102     ``getmtime_func``   Function used to check if templates requires
103                         reloading. Has to return the UNIX timestamp of
104                         the last template change or 0 if this template
105                         does not exist or requires updates at any cost.
106     ``use_memcache``    Set this to ``True`` to enable memory caching.
107                         This is usually a good idea in production mode,
108                         but disable it during development since it won't
109                         reload template changes automatically.
110                         This only works in persistent environments like
111                         FastCGI.
112     ``memcache_size``   Number of template instance you want to cache.
113                         Defaults to ``40``.
114     ``cache_folder``    Set this to an existing directory to enable
115                         caching of templates on the file system. Note
116                         that this only affects templates transformed
117                         into python code. Default is ``None`` which means
118                         that caching is disabled.
119     ``auto_reload``     Set this to `False` for a slightly better
120                         performance. In that case of `getmtime_func`
121                         not being provided this won't have an effect.
122     =================== =================================================
123     """
124     if 'environment' in options:
125         env = options['environment']
126         if not len(options) == 1:
127             raise TypeError('if environment provided no other '
128                             'arguments are allowed')
129     else:
130         loader_func = options.pop('loader_func', None)
131         getmtime_func = options.pop('getmtime_func', None)
132         use_memcache = options.pop('use_memcache', False)
133         memcache_size = options.pop('memcache_size', 40)
134         cache_folder = options.pop('cache_folder', None)
135         auto_reload = options.pop('auto_reload', True)
136         if 'searchpath' in options:
137             options['loader'] = FileSystemLoader(options.pop('searchpath'),
138                                                  use_memcache, memcache_size,
139                                                  cache_folder, auto_reload)
140         elif 'package' in options:
141             options['loader'] = PackageLoader(options.pop('package'),
142                                               options.pop('package_path', ''),
143                                               use_memcache, memcache_size,
144                                               cache_folder, auto_reload)
145         elif loader_func is not None:
146             options['loader'] = FunctionLoader(loader_func, getmtime_func,
147                                                use_memcache, memcache_size,
148                                                cache_folder, auto_reload)
149         env = Environment(**options)
150
151     def render_function(template, values, options):
152         if options.get('is_string'):
153             tmpl = env.from_string(template)
154         else:
155             try:
156                 tmpl = env.get_template(template)
157             except TemplateNotFound:
158                 return
159         return tmpl.render(**values)
160
161     return render_function