Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/jinja2/environment.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/jinja2/environment.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1362 +0,0 @@ -# -*- coding: utf-8 -*- -"""Classes for managing templates and their runtime and compile time -options. -""" -import os -import sys -import weakref -from functools import partial -from functools import reduce - -from markupsafe import Markup - -from . import nodes -from ._compat import encode_filename -from ._compat import implements_iterator -from ._compat import implements_to_string -from ._compat import iteritems -from ._compat import PY2 -from ._compat import PYPY -from ._compat import reraise -from ._compat import string_types -from ._compat import text_type -from .compiler import CodeGenerator -from .compiler import generate -from .defaults import BLOCK_END_STRING -from .defaults import BLOCK_START_STRING -from .defaults import COMMENT_END_STRING -from .defaults import COMMENT_START_STRING -from .defaults import DEFAULT_FILTERS -from .defaults import DEFAULT_NAMESPACE -from .defaults import DEFAULT_POLICIES -from .defaults import DEFAULT_TESTS -from .defaults import KEEP_TRAILING_NEWLINE -from .defaults import LINE_COMMENT_PREFIX -from .defaults import LINE_STATEMENT_PREFIX -from .defaults import LSTRIP_BLOCKS -from .defaults import NEWLINE_SEQUENCE -from .defaults import TRIM_BLOCKS -from .defaults import VARIABLE_END_STRING -from .defaults import VARIABLE_START_STRING -from .exceptions import TemplateNotFound -from .exceptions import TemplateRuntimeError -from .exceptions import TemplatesNotFound -from .exceptions import TemplateSyntaxError -from .exceptions import UndefinedError -from .lexer import get_lexer -from .lexer import TokenStream -from .nodes import EvalContext -from .parser import Parser -from .runtime import Context -from .runtime import new_context -from .runtime import Undefined -from .utils import concat -from .utils import consume -from .utils import have_async_gen -from .utils import import_string -from .utils import internalcode -from .utils import LRUCache -from .utils import missing - -# for direct template usage we have up to ten living environments -_spontaneous_environments = LRUCache(10) - - -def get_spontaneous_environment(cls, *args): - """Return a new spontaneous environment. A spontaneous environment - is used for templates created directly rather than through an - existing environment. - - :param cls: Environment class to create. - :param args: Positional arguments passed to environment. - """ - key = (cls, args) - - try: - return _spontaneous_environments[key] - except KeyError: - _spontaneous_environments[key] = env = cls(*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 instantiated environments. - """ - result = {} - for extension in extensions: - if isinstance(extension, string_types): - extension = import_string(extension) - result[extension.identifier] = extension(environment) - return result - - -def fail_for_missing_callable(string, name): - msg = string % name - if isinstance(name, Undefined): - try: - name._fail_with_undefined_error() - except Exception as e: - msg = "%s (%s; did you forget to quote the callable name?)" % (msg, e) - raise TemplateRuntimeError(msg) - - -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 are the possible initialization parameters: - - `block_start_string` - The string marking the beginning 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 beginning 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 beginning 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 - 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`. - - `lstrip_blocks` - If this is set to ``True`` leading spaces and tabs are stripped - from the start of a line to a block. 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. - - `keep_trailing_newline` - Preserve the trailing newline when rendering templates. - The default is ``False``, which causes a single newline, - if present, to be stripped from the end of the template. - - .. versionadded:: 2.7 - - `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 by - default. For more details about autoescaping see - :class:`~markupsafe.Markup`. As of Jinja 2.4 this can also - be a callable that is passed the template name and has to - return ``True`` or ``False`` depending on autoescape should be - enabled by default. - - .. versionchanged:: 2.4 - `autoescape` can now be a function - - `loader` - The template loader for this environment. - - `cache_size` - The size of the cache. Per default this is ``400`` which means - that if more than 400 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. - - .. versionchanged:: 2.8 - The cache size was increased to 400 from a low 50. - - `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. - - `enable_async` - If set to true this enables async template execution which allows - you to take advantage of newer Python features. This requires - Python 3.6 or later. - """ - - #: 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. This flag alone controls the code - #: generation by the compiler. - 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 - - #: the class that is used for code generation. See - #: :class:`~jinja2.compiler.CodeGenerator` for more information. - code_generator_class = CodeGenerator - - #: the context class thatis used for templates. See - #: :class:`~jinja2.runtime.Context` for more information. - context_class = Context - - 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, - lstrip_blocks=LSTRIP_BLOCKS, - newline_sequence=NEWLINE_SEQUENCE, - keep_trailing_newline=KEEP_TRAILING_NEWLINE, - extensions=(), - optimized=True, - undefined=Undefined, - finalize=None, - autoescape=False, - loader=None, - cache_size=400, - auto_reload=True, - bytecode_cache=None, - enable_async=False, - ): - # !!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: - # - spontaneous 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.lstrip_blocks = lstrip_blocks - self.newline_sequence = newline_sequence - self.keep_trailing_newline = keep_trailing_newline - - # 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.cache = create_cache(cache_size) - self.bytecode_cache = bytecode_cache - self.auto_reload = auto_reload - - # configurable policies - self.policies = DEFAULT_POLICIES.copy() - - # load extensions - self.extensions = load_extensions(self, extensions) - - self.enable_async = enable_async - self.is_async = self.enable_async and have_async_gen - if self.is_async: - # runs patch_all() to enable async support - from . import asyncsupport # noqa: F401 - - _environment_sanity_check(self) - - def add_extension(self, extension): - """Adds an extension after the environment was created. - - .. versionadded:: 2.5 - """ - self.extensions.update(load_extensions(self, [extension])) - - 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 iteritems(attributes): - 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, - lstrip_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 for 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 iteritems(args): - 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 iteritems(self.extensions): - rv.extensions[key] = value.bind(rv) - if extensions is not missing: - rv.extensions.update(load_extensions(rv, extensions)) - - return _environment_sanity_check(rv) - - lexer = property(get_lexer, doc="The lexer for this environment.") - - def iter_extensions(self): - """Iterates over the extensions by priority.""" - return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) - - def getitem(self, obj, argument): - """Get an item or attribute of an object but prefer the item.""" - try: - return obj[argument] - except (AttributeError, TypeError, LookupError): - if isinstance(argument, string_types): - try: - attr = str(argument) - except Exception: - 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) - - def call_filter( - self, name, value, args=None, kwargs=None, context=None, eval_ctx=None - ): - """Invokes a filter on a value the same way the compiler does it. - - Note that on Python 3 this might return a coroutine in case the - filter is running from an environment in async mode and the filter - supports async execution. It's your responsibility to await this - if needed. - - .. versionadded:: 2.7 - """ - func = self.filters.get(name) - if func is None: - fail_for_missing_callable("no filter named %r", name) - args = [value] + list(args or ()) - if getattr(func, "contextfilter", False) is True: - if context is None: - raise TemplateRuntimeError( - "Attempted to invoke context filter without context" - ) - args.insert(0, context) - elif getattr(func, "evalcontextfilter", False) is True: - if eval_ctx is None: - if context is not None: - eval_ctx = context.eval_ctx - else: - eval_ctx = EvalContext(self) - args.insert(0, eval_ctx) - elif getattr(func, "environmentfilter", False) is True: - args.insert(0, self) - return func(*args, **(kwargs or {})) - - def call_test(self, name, value, args=None, kwargs=None): - """Invokes a test on a value the same way the compiler does it. - - .. versionadded:: 2.7 - """ - func = self.tests.get(name) - if func is None: - fail_for_missing_callable("no test named %r", name) - return func(value, *(args or ()), **(kwargs or {})) - - @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 Jinja extensions <writing-extensions>` - this gives you a good overview of the node tree generated. - """ - try: - return self._parse(source, name, filename) - except TemplateSyntaxError: - self.handle_exception(source=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 = text_type(source) - try: - return self.lexer.tokeniter(source, name, filename) - except TemplateSyntaxError: - self.handle_exception(source=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.iter_extensions(), - text_type(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.iter_extensions(): - stream = ext.filter_stream(stream) - if not isinstance(stream, TokenStream): - stream = TokenStream(stream, name, filename) - return stream - - def _generate(self, source, name, filename, defer_init=False): - """Internal hook that can be overridden to hook a different generate - method in. - - .. versionadded:: 2.5 - """ - return generate( - source, - self, - name, - filename, - defer_init=defer_init, - optimized=self.optimized, - ) - - def _compile(self, source, filename): - """Internal hook that can be overridden to hook a different compile - method in. - - .. versionadded:: 2.5 - """ - return compile(source, filename, "exec") - - @internalcode - def compile(self, source, name=None, filename=None, raw=False, defer_init=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. - - `defer_init` is use internally to aid the module code generator. This - causes the generated code to be able to import without the global - environment variable to be set. - - .. versionadded:: 2.4 - `defer_init` parameter added. - """ - source_hint = None - try: - if isinstance(source, string_types): - source_hint = source - source = self._parse(source, name, filename) - source = self._generate(source, name, filename, defer_init=defer_init) - if raw: - return source - if filename is None: - filename = "<template>" - else: - filename = encode_filename(filename) - return self._compile(source, filename) - except TemplateSyntaxError: - self.handle_exception(source=source_hint) - - 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") - try: - expr = parser.parse_expression() - if not parser.stream.eos: - raise TemplateSyntaxError( - "chunk after expression", parser.stream.current.lineno, None, None - ) - expr.set_environment(self) - except TemplateSyntaxError: - if sys.exc_info() is not None: - self.handle_exception(source=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 compile_templates( - self, - target, - extensions=None, - filter_func=None, - zip="deflated", - log_function=None, - ignore_errors=True, - py_compile=False, - ): - """Finds all the templates the loader can find, compiles them - and stores them in `target`. If `zip` is `None`, instead of in a - zipfile, the templates will be stored in a directory. - By default a deflate zip algorithm is used. To switch to - the stored algorithm, `zip` can be set to ``'stored'``. - - `extensions` and `filter_func` are passed to :meth:`list_templates`. - Each template returned will be compiled to the target folder or - zipfile. - - By default template compilation errors are ignored. In case a - log function is provided, errors are logged. If you want template - syntax errors to abort the compilation you can set `ignore_errors` - to `False` and you will get an exception on syntax errors. - - If `py_compile` is set to `True` .pyc files will be written to the - target instead of standard .py files. This flag does not do anything - on pypy and Python 3 where pyc files are not picked up by itself and - don't give much benefit. - - .. versionadded:: 2.4 - """ - from .loaders import ModuleLoader - - if log_function is None: - - def log_function(x): - pass - - if py_compile: - if not PY2 or PYPY: - import warnings - - warnings.warn( - "'py_compile=True' has no effect on PyPy or Python" - " 3 and will be removed in version 3.0", - DeprecationWarning, - stacklevel=2, - ) - py_compile = False - else: - import imp - import marshal - - py_header = imp.get_magic() + u"\xff\xff\xff\xff".encode("iso-8859-15") - - # Python 3.3 added a source filesize to the header - if sys.version_info >= (3, 3): - py_header += u"\x00\x00\x00\x00".encode("iso-8859-15") - - def write_file(filename, data): - if zip: - info = ZipInfo(filename) - info.external_attr = 0o755 << 16 - zip_file.writestr(info, data) - else: - if isinstance(data, text_type): - data = data.encode("utf8") - - with open(os.path.join(target, filename), "wb") as f: - f.write(data) - - if zip is not None: - from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED - - zip_file = ZipFile( - target, "w", dict(deflated=ZIP_DEFLATED, stored=ZIP_STORED)[zip] - ) - log_function('Compiling into Zip archive "%s"' % target) - else: - if not os.path.isdir(target): - os.makedirs(target) - log_function('Compiling into folder "%s"' % target) - - try: - for name in self.list_templates(extensions, filter_func): - source, filename, _ = self.loader.get_source(self, name) - try: - code = self.compile(source, name, filename, True, True) - except TemplateSyntaxError as e: - if not ignore_errors: - raise - log_function('Could not compile "%s": %s' % (name, e)) - continue - - filename = ModuleLoader.get_module_filename(name) - - if py_compile: - c = self._compile(code, encode_filename(filename)) - write_file(filename + "c", py_header + marshal.dumps(c)) - log_function('Byte-compiled "%s" as %s' % (name, filename + "c")) - else: - write_file(filename, code) - log_function('Compiled "%s" as %s' % (name, filename)) - finally: - if zip: - zip_file.close() - - log_function("Finished compiling templates") - - def list_templates(self, extensions=None, filter_func=None): - """Returns a list of templates for this environment. This requires - that the loader supports the loader's - :meth:`~BaseLoader.list_templates` method. - - If there are other files in the template folder besides the - actual templates, the returned list can be filtered. There are two - ways: either `extensions` is set to a list of file extensions for - templates, or a `filter_func` can be provided which is a callable that - is passed a template name and should return `True` if it should end up - in the result list. - - If the loader does not support that, a :exc:`TypeError` is raised. - - .. versionadded:: 2.4 - """ - names = self.loader.list_templates() - - if extensions is not None: - if filter_func is not None: - raise TypeError( - "either extensions or filter_func can be passed, but not both" - ) - - def filter_func(x): - return "." in x and x.rsplit(".", 1)[1] in extensions - - if filter_func is not None: - names = [name for name in names if filter_func(name)] - - return names - - def handle_exception(self, source=None): - """Exception handling helper. This is used internally to either raise - rewritten exceptions or return a rendered traceback for the template. - """ - from .debug import rewrite_traceback_stack - - reraise(*rewrite_traceback_stack(source=source)) - - 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") - cache_key = (weakref.ref(self.loader), name) - if self.cache is not None: - template = self.cache.get(cache_key) - 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[cache_key] = 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 asks 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. - - .. versionchanged:: 2.4 - If `name` is a :class:`Template` object it is returned from the - function unchanged. - """ - 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. - - .. versionchanged:: 2.11 - If names is :class:`Undefined`, an :exc:`UndefinedError` is - raised instead. If no templates were found and names - contains :class:`Undefined`, the message is more helpful. - - .. versionchanged:: 2.4 - If `names` contains a :class:`Template` object it is returned - from the function unchanged. - - .. versionadded:: 2.3 - """ - if isinstance(names, Undefined): - names._fail_with_undefined_error() - - 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, UndefinedError): - 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, (string_types, Undefined)): - 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!' - True - >>> stream = template.stream(name='John Doe') - >>> next(stream) == u'Hello John Doe!' - True - >>> next(stream) - Traceback (most recent call last): - ... - StopIteration - """ - - #: Type of environment to create when creating a template directly - #: rather than through an existing environment. - environment_class = Environment - - 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, - lstrip_blocks=LSTRIP_BLOCKS, - newline_sequence=NEWLINE_SEQUENCE, - keep_trailing_newline=KEEP_TRAILING_NEWLINE, - extensions=(), - optimized=True, - undefined=Undefined, - finalize=None, - autoescape=False, - enable_async=False, - ): - env = get_spontaneous_environment( - cls.environment_class, - 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, - lstrip_blocks, - newline_sequence, - keep_trailing_newline, - frozenset(extensions), - optimized, - undefined, - finalize, - autoescape, - None, - 0, - False, - None, - enable_async, - ) - 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. - """ - namespace = {"environment": environment, "__file__": code.co_filename} - exec(code, namespace) - rv = cls._from_namespace(environment, namespace, globals) - rv._uptodate = uptodate - return rv - - @classmethod - def from_module_dict(cls, environment, module_dict, globals): - """Creates a template object from a module. This is used by the - module loader to create a template object. - - .. versionadded:: 2.4 - """ - return cls._from_namespace(environment, module_dict, globals) - - @classmethod - def _from_namespace(cls, environment, namespace, globals): - t = object.__new__(cls) - t.environment = environment - t.globals = globals - t.name = namespace["name"] - t.filename = namespace["__file__"] - 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 = None - - # store the reference - namespace["environment"] = environment - namespace["__jinja_template__"] = t - - 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 Exception: - self.environment.handle_exception() - - def render_async(self, *args, **kwargs): - """This works similar to :meth:`render` but returns a coroutine - that when awaited returns the entire rendered template string. This - requires the async feature to be enabled. - - Example usage:: - - await template.render_async(knights='that say nih; asynchronously') - """ - # see asyncsupport for the actual implementation - raise NotImplementedError( - "This feature is not available for this version of Python" - ) - - 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 Exception: - yield self.environment.handle_exception() - - def generate_async(self, *args, **kwargs): - """An async version of :meth:`generate`. Works very similarly but - returns an async iterator instead. - """ - # see asyncsupport for the actual implementation - raise NotImplementedError( - "This feature is not available for this version of Python" - ) - - 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 is 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)) - - def make_module_async(self, vars=None, shared=False, locals=None): - """As template module creation can invoke template code for - asynchronous executions this method must be used instead of the - normal :meth:`make_module` one. Likewise the module attribute - becomes unavailable in async mode. - """ - # see asyncsupport for the actual implementation - raise NotImplementedError( - "This feature is not available for this version of Python" - ) - - @internalcode - def _get_default_module(self): - if self._module is not None: - return self._module - self._module = rv = self.make_module() - return rv - - @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') - >>> str(t.module) - '23' - >>> t.module.foo() == u'42' - True - - This attribute is not available if async mode is enabled. - """ - return self._get_default_module() - - 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.""" - if self._debug_info: - return [tuple(map(int, x.split("="))) for x in self._debug_info.split("&")] - return [] - - 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) - - -@implements_to_string -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, body_stream=None): - if body_stream is None: - if context.environment.is_async: - raise RuntimeError( - "Async mode requires a body stream " - "to be passed to a template module. Use " - "the async methods of the API you are " - "using." - ) - body_stream = list(template.root_render_func(context)) - self._body_stream = body_stream - self.__dict__.update(context.get_exported()) - self.__name__ = template.name - - def __html__(self): - return Markup(concat(self._body_stream)) - - def __str__(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 - - -@implements_iterator -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 specify an `encoding`. - - Example usage:: - - Template('Hello {{ name }}!').stream(name='foo').dump('hello.html') - """ - close = False - if isinstance(fp, string_types): - if encoding is None: - encoding = "utf-8" - fp = open(fp, "wb") - 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 = partial(next, self._gen) - self.buffered = False - - def _buffered_generator(self, size): - buf = [] - c_size = 0 - push = buf.append - - while 1: - try: - while c_size < size: - c = next(self._gen) - push(c) - if c: - c_size += 1 - except StopIteration: - if not c_size: - return - yield concat(buf) - del buf[:] - c_size = 0 - - def enable_buffering(self, size=5): - """Enable buffering. Buffer `size` items before yielding them.""" - if size <= 1: - raise ValueError("buffer size too small") - - self.buffered = True - self._next = partial(next, self._buffered_generator(size)) - - 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