| # -*- coding: utf-8 -*- |
| """ |
| jinja2.environment |
| ~~~~~~~~~~~~~~~~~~ |
| |
| Provides a class that holds runtime and parsing time options. |
| |
| :copyright: (c) 2010 by the Jinja Team. |
| :license: BSD, see LICENSE for more details. |
| """ |
| import sys |
| from jinja2 import nodes |
| from jinja2.defaults import * |
| from jinja2.lexer import get_lexer, TokenStream |
| from jinja2.parser import Parser |
| from jinja2.optimizer import optimize |
| from jinja2.compiler import generate |
| from jinja2.runtime import Undefined, new_context |
| from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, \ |
| TemplatesNotFound |
| from jinja2.utils import import_string, LRUCache, Markup, missing, \ |
| concat, consume, internalcode, _encode_filename |
| |
| |
| # for direct template usage we have up to ten living environments |
| _spontaneous_environments = LRUCache(10) |
| |
| # the function to create jinja traceback objects. This is dynamically |
| # imported on the first exception in the exception handler. |
| _make_traceback = None |
| |
| |
| def get_spontaneous_environment(*args): |
| """Return a new spontaneous environment. A spontaneous environment is an |
| unnamed and unaccessible (in theory) environment that is used for |
| templates generated from a string and not from the file system. |
| """ |
| try: |
| env = _spontaneous_environments.get(args) |
| except TypeError: |
| return Environment(*args) |
| if env is not None: |
| return env |
| _spontaneous_environments[args] = env = Environment(*args) |
| env.shared = True |
| return env |
| |
| |
| def create_cache(size): |
| """Return the cache class for the given size.""" |
| if size == 0: |
| return None |
| if size < 0: |
| return {} |
| return LRUCache(size) |
| |
| |
| def copy_cache(cache): |
| """Create an empty copy of the given cache.""" |
| if cache is None: |
| return None |
| elif type(cache) is dict: |
| return {} |
| return LRUCache(cache.capacity) |
| |
| |
| def load_extensions(environment, extensions): |
| """Load the extensions from the list and bind it to the environment. |
| Returns a dict of instanciated environments. |
| """ |
| result = {} |
| for extension in extensions: |
| if isinstance(extension, basestring): |
| extension = import_string(extension) |
| result[extension.identifier] = extension(environment) |
| return result |
| |
| |
| def _environment_sanity_check(environment): |
| """Perform a sanity check on the environment.""" |
| assert issubclass(environment.undefined, Undefined), 'undefined must ' \ |
| 'be a subclass of undefined because filters depend on it.' |
| assert environment.block_start_string != \ |
| environment.variable_start_string != \ |
| environment.comment_start_string, 'block, variable and comment ' \ |
| 'start strings must be different' |
| assert environment.newline_sequence in ('\r', '\r\n', '\n'), \ |
| 'newline_sequence set to unknown line ending string.' |
| return environment |
| |
| |
| class Environment(object): |
| r"""The core component of Jinja is the `Environment`. It contains |
| important shared variables like configuration, filters, tests, |
| globals and others. Instances of this class may be modified if |
| they are not shared and if no template was loaded so far. |
| Modifications on environments after the first template was loaded |
| will lead to surprising effects and undefined behavior. |
| |
| Here the possible initialization parameters: |
| |
| `block_start_string` |
| The string marking the begin of a block. Defaults to ``'{%'``. |
| |
| `block_end_string` |
| The string marking the end of a block. Defaults to ``'%}'``. |
| |
| `variable_start_string` |
| The string marking the begin of a print statement. |
| Defaults to ``'{{'``. |
| |
| `variable_end_string` |
| The string marking the end of a print statement. Defaults to |
| ``'}}'``. |
| |
| `comment_start_string` |
| The string marking the begin of a comment. Defaults to ``'{#'``. |
| |
| `comment_end_string` |
| The string marking the end of a comment. Defaults to ``'#}'``. |
| |
| `line_statement_prefix` |
| If given and a string, this will be used as prefix for line based |
| statements. See also :ref:`line-statements`. |
| |
| `line_comment_prefix` |
| If given and a string, this will be used as prefix for line based |
| based comments. See also :ref:`line-statements`. |
| |
| .. versionadded:: 2.2 |
| |
| `trim_blocks` |
| If this is set to ``True`` the first newline after a block is |
| removed (block, not variable tag!). Defaults to `False`. |
| |
| `newline_sequence` |
| The sequence that starts a newline. Must be one of ``'\r'``, |
| ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a |
| useful default for Linux and OS X systems as well as web |
| applications. |
| |
| `extensions` |
| List of Jinja extensions to use. This can either be import paths |
| as strings or extension classes. For more information have a |
| look at :ref:`the extensions documentation <jinja-extensions>`. |
| |
| `optimized` |
| should the optimizer be enabled? Default is `True`. |
| |
| `undefined` |
| :class:`Undefined` or a subclass of it that is used to represent |
| undefined values in the template. |
| |
| `finalize` |
| A callable that can be used to process the result of a variable |
| expression before it is output. For example one can convert |
| `None` implicitly into an empty string here. |
| |
| `autoescape` |
| If set to true the XML/HTML autoescaping feature is enabled. |
| For more details about auto escaping see |
| :class:`~jinja2.utils.Markup`. |
| |
| `loader` |
| The template loader for this environment. |
| |
| `cache_size` |
| The size of the cache. Per default this is ``50`` which means |
| that if more than 50 templates are loaded the loader will clean |
| out the least recently used template. If the cache size is set to |
| ``0`` templates are recompiled all the time, if the cache size is |
| ``-1`` the cache will not be cleaned. |
| |
| `auto_reload` |
| Some loaders load templates from locations where the template |
| sources may change (ie: file system or database). If |
| `auto_reload` is set to `True` (default) every time a template is |
| requested the loader checks if the source changed and if yes, it |
| will reload the template. For higher performance it's possible to |
| disable that. |
| |
| `bytecode_cache` |
| If set to a bytecode cache object, this object will provide a |
| cache for the internal Jinja bytecode so that templates don't |
| have to be parsed if they were not changed. |
| |
| See :ref:`bytecode-cache` for more information. |
| """ |
| |
| #: if this environment is sandboxed. Modifying this variable won't make |
| #: the environment sandboxed though. For a real sandboxed environment |
| #: have a look at jinja2.sandbox |
| sandboxed = False |
| |
| #: True if the environment is just an overlay |
| overlayed = False |
| |
| #: the environment this environment is linked to if it is an overlay |
| linked_to = None |
| |
| #: shared environments have this set to `True`. A shared environment |
| #: must not be modified |
| shared = False |
| |
| #: these are currently EXPERIMENTAL undocumented features. |
| exception_handler = None |
| exception_formatter = None |
| |
| def __init__(self, |
| block_start_string=BLOCK_START_STRING, |
| block_end_string=BLOCK_END_STRING, |
| variable_start_string=VARIABLE_START_STRING, |
| variable_end_string=VARIABLE_END_STRING, |
| comment_start_string=COMMENT_START_STRING, |
| comment_end_string=COMMENT_END_STRING, |
| line_statement_prefix=LINE_STATEMENT_PREFIX, |
| line_comment_prefix=LINE_COMMENT_PREFIX, |
| trim_blocks=TRIM_BLOCKS, |
| newline_sequence=NEWLINE_SEQUENCE, |
| extensions=(), |
| optimized=True, |
| undefined=Undefined, |
| finalize=None, |
| autoescape=False, |
| loader=None, |
| cache_size=50, |
| auto_reload=True, |
| bytecode_cache=None): |
| # !!Important notice!! |
| # The constructor accepts quite a few arguments that should be |
| # passed by keyword rather than position. However it's important to |
| # not change the order of arguments because it's used at least |
| # internally in those cases: |
| # - spontaneus environments (i18n extension and Template) |
| # - unittests |
| # If parameter changes are required only add parameters at the end |
| # and don't change the arguments (or the defaults!) of the arguments |
| # existing already. |
| |
| # 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 |
| self.line_statement_prefix = line_statement_prefix |
| self.line_comment_prefix = line_comment_prefix |
| self.trim_blocks = trim_blocks |
| self.newline_sequence = newline_sequence |
| |
| # runtime information |
| self.undefined = undefined |
| self.optimized = optimized |
| self.finalize = finalize |
| self.autoescape = autoescape |
| |
| # defaults |
| self.filters = DEFAULT_FILTERS.copy() |
| self.tests = DEFAULT_TESTS.copy() |
| self.globals = DEFAULT_NAMESPACE.copy() |
| |
| # set the loader provided |
| self.loader = loader |
| self.bytecode_cache = None |
| self.cache = create_cache(cache_size) |
| self.bytecode_cache = bytecode_cache |
| self.auto_reload = auto_reload |
| |
| # load extensions |
| self.extensions = load_extensions(self, extensions) |
| |
| _environment_sanity_check(self) |
| |
| def extend(self, **attributes): |
| """Add the items to the instance of the environment if they do not exist |
| yet. This is used by :ref:`extensions <writing-extensions>` to register |
| callbacks and configuration values without breaking inheritance. |
| """ |
| for key, value in attributes.iteritems(): |
| if not hasattr(self, key): |
| setattr(self, key, value) |
| |
| def overlay(self, block_start_string=missing, block_end_string=missing, |
| variable_start_string=missing, variable_end_string=missing, |
| comment_start_string=missing, comment_end_string=missing, |
| line_statement_prefix=missing, line_comment_prefix=missing, |
| trim_blocks=missing, extensions=missing, optimized=missing, |
| undefined=missing, finalize=missing, autoescape=missing, |
| loader=missing, cache_size=missing, auto_reload=missing, |
| bytecode_cache=missing): |
| """Create a new overlay environment that shares all the data with the |
| current environment except of cache and the overridden attributes. |
| Extensions cannot be removed for an overlayed environment. An overlayed |
| environment automatically gets all the extensions of the environment it |
| is linked to plus optional extra extensions. |
| |
| Creating overlays should happen after the initial environment was set |
| up completely. Not all attributes are truly linked, some are just |
| copied over so modifications on the original environment may not shine |
| through. |
| """ |
| args = dict(locals()) |
| del args['self'], args['cache_size'], args['extensions'] |
| |
| rv = object.__new__(self.__class__) |
| rv.__dict__.update(self.__dict__) |
| rv.overlayed = True |
| rv.linked_to = self |
| |
| for key, value in args.iteritems(): |
| if value is not missing: |
| setattr(rv, key, value) |
| |
| if cache_size is not missing: |
| rv.cache = create_cache(cache_size) |
| else: |
| rv.cache = copy_cache(self.cache) |
| |
| rv.extensions = {} |
| for key, value in self.extensions.iteritems(): |
| rv.extensions[key] = value.bind(rv) |
| if extensions is not missing: |
| rv.extensions.update(load_extensions(extensions)) |
| |
| return _environment_sanity_check(rv) |
| |
| lexer = property(get_lexer, doc="The lexer for this environment.") |
| |
| def getitem(self, obj, argument): |
| """Get an item or attribute of an object but prefer the item.""" |
| try: |
| return obj[argument] |
| except (TypeError, LookupError): |
| if isinstance(argument, basestring): |
| try: |
| attr = str(argument) |
| except: |
| pass |
| else: |
| try: |
| return getattr(obj, attr) |
| except AttributeError: |
| pass |
| return self.undefined(obj=obj, name=argument) |
| |
| def getattr(self, obj, attribute): |
| """Get an item or attribute of an object but prefer the attribute. |
| Unlike :meth:`getitem` the attribute *must* be a bytestring. |
| """ |
| try: |
| return getattr(obj, attribute) |
| except AttributeError: |
| pass |
| try: |
| return obj[attribute] |
| except (TypeError, LookupError, AttributeError): |
| return self.undefined(obj=obj, name=attribute) |
| |
| @internalcode |
| def parse(self, source, name=None, filename=None): |
| """Parse the sourcecode and return the abstract syntax tree. This |
| tree of nodes is used by the compiler to convert the template into |
| executable source- or bytecode. This is useful for debugging or to |
| extract information from templates. |
| |
| If you are :ref:`developing Jinja2 extensions <writing-extensions>` |
| this gives you a good overview of the node tree generated. |
| """ |
| try: |
| return self._parse(source, name, filename) |
| except TemplateSyntaxError: |
| exc_info = sys.exc_info() |
| self.handle_exception(exc_info, source_hint=source) |
| |
| def _parse(self, source, name, filename): |
| """Internal parsing function used by `parse` and `compile`.""" |
| return Parser(self, source, name, _encode_filename(filename)).parse() |
| |
| def lex(self, source, name=None, filename=None): |
| """Lex the given sourcecode and return a generator that yields |
| tokens as tuples in the form ``(lineno, token_type, value)``. |
| This can be useful for :ref:`extension development <writing-extensions>` |
| and debugging templates. |
| |
| This does not perform preprocessing. If you want the preprocessing |
| of the extensions to be applied you have to filter source through |
| the :meth:`preprocess` method. |
| """ |
| source = unicode(source) |
| try: |
| return self.lexer.tokeniter(source, name, filename) |
| except TemplateSyntaxError: |
| exc_info = sys.exc_info() |
| self.handle_exception(exc_info, source_hint=source) |
| |
| def preprocess(self, source, name=None, filename=None): |
| """Preprocesses the source with all extensions. This is automatically |
| called for all parsing and compiling methods but *not* for :meth:`lex` |
| because there you usually only want the actual source tokenized. |
| """ |
| return reduce(lambda s, e: e.preprocess(s, name, filename), |
| self.extensions.itervalues(), unicode(source)) |
| |
| def _tokenize(self, source, name, filename=None, state=None): |
| """Called by the parser to do the preprocessing and filtering |
| for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. |
| """ |
| source = self.preprocess(source, name, filename) |
| stream = self.lexer.tokenize(source, name, filename, state) |
| for ext in self.extensions.itervalues(): |
| stream = ext.filter_stream(stream) |
| if not isinstance(stream, TokenStream): |
| stream = TokenStream(stream, name, filename) |
| return stream |
| |
| @internalcode |
| def compile(self, source, name=None, filename=None, raw=False): |
| """Compile a node or template source code. The `name` parameter is |
| the load name of the template after it was joined using |
| :meth:`join_path` if necessary, not the filename on the file system. |
| the `filename` parameter is the estimated filename of the template on |
| the file system. If the template came from a database or memory this |
| can be omitted. |
| |
| The return value of this method is a python code object. If the `raw` |
| parameter is `True` the return value will be a string with python |
| code equivalent to the bytecode returned otherwise. This method is |
| mainly used internally. |
| """ |
| source_hint = None |
| try: |
| if isinstance(source, basestring): |
| source_hint = source |
| source = self._parse(source, name, filename) |
| if self.optimized: |
| source = optimize(source, self) |
| source = generate(source, self, name, filename) |
| if raw: |
| return source |
| if filename is None: |
| filename = '<template>' |
| else: |
| filename = _encode_filename(filename) |
| return compile(source, filename, 'exec') |
| except TemplateSyntaxError: |
| exc_info = sys.exc_info() |
| self.handle_exception(exc_info, source_hint=source) |
| |
| def compile_expression(self, source, undefined_to_none=True): |
| """A handy helper method that returns a callable that accepts keyword |
| arguments that appear as variables in the expression. If called it |
| returns the result of the expression. |
| |
| This is useful if applications want to use the same rules as Jinja |
| in template "configuration files" or similar situations. |
| |
| Example usage: |
| |
| >>> env = Environment() |
| >>> expr = env.compile_expression('foo == 42') |
| >>> expr(foo=23) |
| False |
| >>> expr(foo=42) |
| True |
| |
| Per default the return value is converted to `None` if the |
| expression returns an undefined value. This can be changed |
| by setting `undefined_to_none` to `False`. |
| |
| >>> env.compile_expression('var')() is None |
| True |
| >>> env.compile_expression('var', undefined_to_none=False)() |
| Undefined |
| |
| .. versionadded:: 2.1 |
| """ |
| parser = Parser(self, source, state='variable') |
| exc_info = None |
| try: |
| expr = parser.parse_expression() |
| if not parser.stream.eos: |
| raise TemplateSyntaxError('chunk after expression', |
| parser.stream.current.lineno, |
| None, None) |
| except TemplateSyntaxError: |
| exc_info = sys.exc_info() |
| if exc_info is not None: |
| self.handle_exception(exc_info, source_hint=source) |
| body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)] |
| template = self.from_string(nodes.Template(body, lineno=1)) |
| return TemplateExpression(template, undefined_to_none) |
| |
| def handle_exception(self, exc_info=None, rendered=False, source_hint=None): |
| """Exception handling helper. This is used internally to either raise |
| rewritten exceptions or return a rendered traceback for the template. |
| """ |
| global _make_traceback |
| if exc_info is None: |
| exc_info = sys.exc_info() |
| |
| # the debugging module is imported when it's used for the first time. |
| # we're doing a lot of stuff there and for applications that do not |
| # get any exceptions in template rendering there is no need to load |
| # all of that. |
| if _make_traceback is None: |
| from jinja2.debug import make_traceback as _make_traceback |
| traceback = _make_traceback(exc_info, source_hint) |
| if rendered and self.exception_formatter is not None: |
| return self.exception_formatter(traceback) |
| if self.exception_handler is not None: |
| self.exception_handler(traceback) |
| exc_type, exc_value, tb = traceback.standard_exc_info |
| raise exc_type, exc_value, tb |
| |
| def join_path(self, template, parent): |
| """Join a template with the parent. By default all the lookups are |
| relative to the loader root so this method returns the `template` |
| parameter unchanged, but if the paths should be relative to the |
| parent template, this function can be used to calculate the real |
| template name. |
| |
| Subclasses may override this method and implement template path |
| joining here. |
| """ |
| return template |
| |
| @internalcode |
| def _load_template(self, name, globals): |
| if self.loader is None: |
| raise TypeError('no loader for this environment specified') |
| if self.cache is not None: |
| template = self.cache.get(name) |
| if template is not None and (not self.auto_reload or \ |
| template.is_up_to_date): |
| return template |
| template = self.loader.load(self, name, globals) |
| if self.cache is not None: |
| self.cache[name] = template |
| return template |
| |
| @internalcode |
| def get_template(self, name, parent=None, globals=None): |
| """Load a template from the loader. If a loader is configured this |
| method ask the loader for the template and returns a :class:`Template`. |
| If the `parent` parameter is not `None`, :meth:`join_path` is called |
| to get the real template name before loading. |
| |
| The `globals` parameter can be used to provide template wide globals. |
| These variables are available in the context at render time. |
| |
| If the template does not exist a :exc:`TemplateNotFound` exception is |
| raised. |
| """ |
| if isinstance(name, Template): |
| return name |
| if parent is not None: |
| name = self.join_path(name, parent) |
| return self._load_template(name, self.make_globals(globals)) |
| |
| @internalcode |
| def select_template(self, names, parent=None, globals=None): |
| """Works like :meth:`get_template` but tries a number of templates |
| before it fails. If it cannot find any of the templates, it will |
| raise a :exc:`TemplatesNotFound` exception. |
| |
| .. versionadded:: 2.3 |
| """ |
| if not names: |
| raise TemplatesNotFound(message=u'Tried to select from an empty list ' |
| u'of templates.') |
| globals = self.make_globals(globals) |
| for name in names: |
| if isinstance(name, Template): |
| return name |
| if parent is not None: |
| name = self.join_path(name, parent) |
| try: |
| return self._load_template(name, globals) |
| except TemplateNotFound: |
| pass |
| raise TemplatesNotFound(names) |
| |
| @internalcode |
| def get_or_select_template(self, template_name_or_list, |
| parent=None, globals=None): |
| """ |
| Does a typecheck and dispatches to :meth:`select_template` if an |
| iterable of template names is given, otherwise to :meth:`get_template`. |
| |
| .. versionadded:: 2.3 |
| """ |
| if isinstance(template_name_or_list, basestring): |
| return self.get_template(template_name_or_list, parent, globals) |
| elif isinstance(template_name_or_list, Template): |
| return template_name_or_list |
| return self.select_template(template_name_or_list, parent, globals) |
| |
| def from_string(self, source, globals=None, template_class=None): |
| """Load a template from a string. This parses the source given and |
| returns a :class:`Template` object. |
| """ |
| globals = self.make_globals(globals) |
| cls = template_class or self.template_class |
| return cls.from_code(self, self.compile(source), globals, None) |
| |
| def make_globals(self, d): |
| """Return a dict for the globals.""" |
| if not d: |
| return self.globals |
| return dict(self.globals, **d) |
| |
| |
| class Template(object): |
| """The central template object. This class represents a compiled template |
| and is used to evaluate it. |
| |
| Normally the template object is generated from an :class:`Environment` but |
| it also has a constructor that makes it possible to create a template |
| instance directly using the constructor. It takes the same arguments as |
| the environment constructor but it's not possible to specify a loader. |
| |
| Every template object has a few methods and members that are guaranteed |
| to exist. However it's important that a template object should be |
| considered immutable. Modifications on the object are not supported. |
| |
| Template objects created from the constructor rather than an environment |
| do have an `environment` attribute that points to a temporary environment |
| that is probably shared with other templates created with the constructor |
| and compatible settings. |
| |
| >>> template = Template('Hello {{ name }}!') |
| >>> template.render(name='John Doe') |
| u'Hello John Doe!' |
| |
| >>> stream = template.stream(name='John Doe') |
| >>> stream.next() |
| u'Hello John Doe!' |
| >>> stream.next() |
| Traceback (most recent call last): |
| ... |
| StopIteration |
| """ |
| |
| def __new__(cls, source, |
| block_start_string=BLOCK_START_STRING, |
| block_end_string=BLOCK_END_STRING, |
| variable_start_string=VARIABLE_START_STRING, |
| variable_end_string=VARIABLE_END_STRING, |
| comment_start_string=COMMENT_START_STRING, |
| comment_end_string=COMMENT_END_STRING, |
| line_statement_prefix=LINE_STATEMENT_PREFIX, |
| line_comment_prefix=LINE_COMMENT_PREFIX, |
| trim_blocks=TRIM_BLOCKS, |
| newline_sequence=NEWLINE_SEQUENCE, |
| extensions=(), |
| optimized=True, |
| undefined=Undefined, |
| finalize=None, |
| autoescape=False): |
| env = get_spontaneous_environment( |
| block_start_string, block_end_string, variable_start_string, |
| variable_end_string, comment_start_string, comment_end_string, |
| line_statement_prefix, line_comment_prefix, trim_blocks, |
| newline_sequence, frozenset(extensions), optimized, undefined, |
| finalize, autoescape, None, 0, False, None) |
| return env.from_string(source, template_class=cls) |
| |
| @classmethod |
| def from_code(cls, environment, code, globals, uptodate=None): |
| """Creates a template object from compiled code and the globals. This |
| is used by the loaders and environment to create a template object. |
| """ |
| t = object.__new__(cls) |
| namespace = { |
| 'environment': environment, |
| '__jinja_template__': t |
| } |
| exec code in namespace |
| t.environment = environment |
| t.globals = globals |
| t.name = namespace['name'] |
| t.filename = code.co_filename |
| t.blocks = namespace['blocks'] |
| |
| # render function and module |
| t.root_render_func = namespace['root'] |
| t._module = None |
| |
| # debug and loader helpers |
| t._debug_info = namespace['debug_info'] |
| t._uptodate = uptodate |
| |
| return t |
| |
| def render(self, *args, **kwargs): |
| """This method accepts the same arguments as the `dict` constructor: |
| A dict, a dict subclass or some keyword arguments. If no arguments |
| are given the context will be empty. These two calls do the same:: |
| |
| template.render(knights='that say nih') |
| template.render({'knights': 'that say nih'}) |
| |
| This will return the rendered template as unicode string. |
| """ |
| vars = dict(*args, **kwargs) |
| try: |
| return concat(self.root_render_func(self.new_context(vars))) |
| except: |
| exc_info = sys.exc_info() |
| return self.environment.handle_exception(exc_info, True) |
| |
| def stream(self, *args, **kwargs): |
| """Works exactly like :meth:`generate` but returns a |
| :class:`TemplateStream`. |
| """ |
| return TemplateStream(self.generate(*args, **kwargs)) |
| |
| def generate(self, *args, **kwargs): |
| """For very large templates it can be useful to not render the whole |
| template at once but evaluate each statement after another and yield |
| piece for piece. This method basically does exactly that and returns |
| a generator that yields one item after another as unicode strings. |
| |
| It accepts the same arguments as :meth:`render`. |
| """ |
| vars = dict(*args, **kwargs) |
| try: |
| for event in self.root_render_func(self.new_context(vars)): |
| yield event |
| except: |
| exc_info = sys.exc_info() |
| else: |
| return |
| yield self.environment.handle_exception(exc_info, True) |
| |
| def new_context(self, vars=None, shared=False, locals=None): |
| """Create a new :class:`Context` for this template. The vars |
| provided will be passed to the template. Per default the globals |
| are added to the context. If shared is set to `True` the data |
| is passed as it to the context without adding the globals. |
| |
| `locals` can be a dict of local variables for internal usage. |
| """ |
| return new_context(self.environment, self.name, self.blocks, |
| vars, shared, self.globals, locals) |
| |
| def make_module(self, vars=None, shared=False, locals=None): |
| """This method works like the :attr:`module` attribute when called |
| without arguments but it will evaluate the template on every call |
| rather than caching it. It's also possible to provide |
| a dict which is then used as context. The arguments are the same |
| as for the :meth:`new_context` method. |
| """ |
| return TemplateModule(self, self.new_context(vars, shared, locals)) |
| |
| @property |
| def module(self): |
| """The template as module. This is used for imports in the |
| template runtime but is also useful if one wants to access |
| exported template variables from the Python layer: |
| |
| >>> t = Template('{% macro foo() %}42{% endmacro %}23') |
| >>> unicode(t.module) |
| u'23' |
| >>> t.module.foo() |
| u'42' |
| """ |
| if self._module is not None: |
| return self._module |
| self._module = rv = self.make_module() |
| return rv |
| |
| def get_corresponding_lineno(self, lineno): |
| """Return the source line number of a line number in the |
| generated bytecode as they are not in sync. |
| """ |
| for template_line, code_line in reversed(self.debug_info): |
| if code_line <= lineno: |
| return template_line |
| return 1 |
| |
| @property |
| def is_up_to_date(self): |
| """If this variable is `False` there is a newer version available.""" |
| if self._uptodate is None: |
| return True |
| return self._uptodate() |
| |
| @property |
| def debug_info(self): |
| """The debug info mapping.""" |
| return [tuple(map(int, x.split('='))) for x in |
| self._debug_info.split('&')] |
| |
| def __repr__(self): |
| if self.name is None: |
| name = 'memory:%x' % id(self) |
| else: |
| name = repr(self.name) |
| return '<%s %s>' % (self.__class__.__name__, name) |
| |
| |
| class TemplateModule(object): |
| """Represents an imported template. All the exported names of the |
| template are available as attributes on this object. Additionally |
| converting it into an unicode- or bytestrings renders the contents. |
| """ |
| |
| def __init__(self, template, context): |
| self._body_stream = list(template.root_render_func(context)) |
| self.__dict__.update(context.get_exported()) |
| self.__name__ = template.name |
| |
| def __html__(self): |
| return Markup(concat(self._body_stream)) |
| |
| def __str__(self): |
| return unicode(self).encode('utf-8') |
| |
| # unicode goes after __str__ because we configured 2to3 to rename |
| # __unicode__ to __str__. because the 2to3 tree is not designed to |
| # remove nodes from it, we leave the above __str__ around and let |
| # it override at runtime. |
| def __unicode__(self): |
| return concat(self._body_stream) |
| |
| def __repr__(self): |
| if self.__name__ is None: |
| name = 'memory:%x' % id(self) |
| else: |
| name = repr(self.__name__) |
| return '<%s %s>' % (self.__class__.__name__, name) |
| |
| |
| class TemplateExpression(object): |
| """The :meth:`jinja2.Environment.compile_expression` method returns an |
| instance of this object. It encapsulates the expression-like access |
| to the template with an expression it wraps. |
| """ |
| |
| def __init__(self, template, undefined_to_none): |
| self._template = template |
| self._undefined_to_none = undefined_to_none |
| |
| def __call__(self, *args, **kwargs): |
| context = self._template.new_context(dict(*args, **kwargs)) |
| consume(self._template.root_render_func(context)) |
| rv = context.vars['result'] |
| if self._undefined_to_none and isinstance(rv, Undefined): |
| rv = None |
| return rv |
| |
| |
| class TemplateStream(object): |
| """A template stream works pretty much like an ordinary python generator |
| but it can buffer multiple items to reduce the number of total iterations. |
| Per default the output is unbuffered which means that for every unbuffered |
| instruction in the template one unicode string is yielded. |
| |
| If buffering is enabled with a buffer size of 5, five items are combined |
| into a new unicode string. This is mainly useful if you are streaming |
| big templates to a client via WSGI which flushes after each iteration. |
| """ |
| |
| def __init__(self, gen): |
| self._gen = gen |
| self.disable_buffering() |
| |
| def dump(self, fp, encoding=None, errors='strict'): |
| """Dump the complete stream into a file or file-like object. |
| Per default unicode strings are written, if you want to encode |
| before writing specifiy an `encoding`. |
| |
| Example usage:: |
| |
| Template('Hello {{ name }}!').stream(name='foo').dump('hello.html') |
| """ |
| close = False |
| if isinstance(fp, basestring): |
| fp = file(fp, 'w') |
| close = True |
| try: |
| if encoding is not None: |
| iterable = (x.encode(encoding, errors) for x in self) |
| else: |
| iterable = self |
| if hasattr(fp, 'writelines'): |
| fp.writelines(iterable) |
| else: |
| for item in iterable: |
| fp.write(item) |
| finally: |
| if close: |
| fp.close() |
| |
| def disable_buffering(self): |
| """Disable the output buffering.""" |
| self._next = self._gen.next |
| self.buffered = False |
| |
| def enable_buffering(self, size=5): |
| """Enable buffering. Buffer `size` items before yielding them.""" |
| if size <= 1: |
| raise ValueError('buffer size too small') |
| |
| def generator(next): |
| buf = [] |
| c_size = 0 |
| push = buf.append |
| |
| while 1: |
| try: |
| while c_size < size: |
| c = next() |
| push(c) |
| if c: |
| c_size += 1 |
| except StopIteration: |
| if not c_size: |
| return |
| yield concat(buf) |
| del buf[:] |
| c_size = 0 |
| |
| self.buffered = True |
| self._next = generator(self._gen.next).next |
| |
| def __iter__(self): |
| return self |
| |
| def next(self): |
| return self._next() |
| |
| |
| # hook in default template class. if anyone reads this comment: ignore that |
| # it's possible to use custom templates ;-) |
| Environment.template_class = Template |