blob: 92a7618555beb295b1a61eed0336d65395ce5604 [file] [log] [blame]
# -*- coding: utf-8 -*-
"""
jinja.environment
~~~~~~~~~~~~~~~~~
Provides a class that holds runtime and parsing time options.
:copyright: 2006 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from jinja.lexer import Lexer
from jinja.parser import Parser
from jinja.loaders import LoaderWrapper
from jinja.datastructure import Undefined
from jinja.exceptions import FilterNotFound, TestNotFound
from jinja.defaults import DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE
class Environment(object):
"""
The jinja environment.
"""
def __init__(self,
block_start_string='{%',
block_end_string='%}',
variable_start_string='{{',
variable_end_string='}}',
comment_start_string='{#',
comment_end_string='#}',
template_charset='utf-8',
charset='utf-8',
namespace=None,
loader=None,
filters=None,
tests=None):
# lexer / parser information
self.block_start_string = block_start_string
self.block_end_string = block_end_string
self.variable_start_string = variable_start_string
self.variable_end_string = variable_end_string
self.comment_start_string = comment_start_string
self.comment_end_string = comment_end_string
# other stuff
self.template_charset = template_charset
self.charset = charset
self.loader = loader
self.filters = filters is None and DEFAULT_FILTERS.copy() or filters
self.tests = tests is None and DEFAULT_TESTS.copy() or tests
# global namespace
self.globals = namespace is None and DEFAULT_NAMESPACE.copy() \
or namespace
# create lexer
self.lexer = Lexer(self)
def loader(self, value):
"""
Get or set the template loader.
"""
self._loader = LoaderWrapper(self, value)
loader = property(lambda s: s._loader, loader, loader.__doc__)
def parse(self, source):
"""Function that creates a new parser and parses the source."""
parser = Parser(self, source)
return parser.parse_page()
def from_string(self, source):
"""Load a template from a string."""
from jinja.parser import Parser
from jinja.translators.python import PythonTranslator
return PythonTranslator.process(self, Parser(self, source).parse())
def to_unicode(self, value):
"""
Convert a value to unicode with the rules defined on the environment.
"""
if isinstance(value, unicode):
return value
else:
try:
return unicode(value)
except UnicodeError:
return str(value).decode(self.charset, 'ignore')
def prepare_filter(self, name, *args):
"""
Prepare a filter.
"""
try:
return self.filters[name](*args)
except KeyError:
raise FilterNotFound(name)
def apply_filters(self, value, context, filters):
"""
Apply a list of filters on the variable.
"""
for f in filters:
value = f(self, context, value)
return value
def perform_test(self, value, context, testname):
"""
Perform a test on a variable.
"""
try:
test = self.tests[testname]
except KeyError:
raise TestNotFound(testname)
return bool(test(self, context, value))
def get_attribute(self, obj, name):
"""
Get the attribute name from obj.
"""
try:
rv = getattr(obj, name)
r = getattr(obj, 'jinja_allowed_attributes', None)
if r is not None:
if name not in r:
raise AttributeError()
return rv
except AttributeError:
return obj[name]
except:
return Undefined
def call_function(self, f, args, kwargs, dyn_args, dyn_kwargs):
"""
Function call helper
"""
if dyn_args is not None:
args += dyn_args
elif dyn_kwargs is not None:
kwargs.update(dyn_kwargs)
return f(*args, **kwargs)
def finish_var(self, value):
"""
As long as no write_var function is passed to the template
evaluator the source generated by the python translator will
call this function for all variables. You can use this to
enable output escaping etc or just ensure that None and
Undefined values are rendered as empty strings.
"""
if value is None or value is Undefined:
return u''
return unicode(value)