1b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# -*- coding: utf-8 -*- 2b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)""" 3b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) jinja2.ext 4b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ~~~~~~~~~~ 5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 6b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) Jinja extensions allow to add custom tags similar to the way django custom 7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tags work. By default two example extensions exist: an i18n and a cache 8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) extension. 9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :copyright: (c) 2010 by the Jinja Team. 11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :license: BSD. 12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)""" 13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from jinja2 import nodes 1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from jinja2.defaults import BLOCK_START_STRING, \ 1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \ 1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \ 1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \ 1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS 19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from jinja2.environment import Environment 2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from jinja2.runtime import concat 21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from jinja2.utils import contextfunction, import_string, Markup 2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from jinja2._compat import next, with_metaclass, string_types, iteritems 24b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 25b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 26b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# the only real useful gettext functions for a Jinja template. Note 27b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# that ugettext must be assigned to gettext as Jinja doesn't support 28b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# non unicode strings. 29b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)GETTEXT_FUNCTIONS = ('_', 'gettext', 'ngettext') 30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 31b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class ExtensionRegistry(type): 33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Gives the extension an unique identifier.""" 34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __new__(cls, name, bases, d): 36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv = type.__new__(cls, name, bases, d) 37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv.identifier = rv.__module__ + '.' + rv.__name__ 38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return rv 39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class Extension(with_metaclass(ExtensionRegistry, object)): 42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Extensions can be used to add extra functionality to the Jinja template 43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) system at the parser level. Custom extensions are bound to an environment 44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) but may not store environment specific data on `self`. The reason for 45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) this is that an extension can be bound to another environment (for 46b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) overlays) by creating a copy and reassigning the `environment` attribute. 47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) As extensions are created by the environment they cannot accept any 49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) arguments for configuration. One may want to work around that by using 50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) a factory function, but that is not possible as extensions are identified 51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) by their import name. The correct way to configure the extension is 52b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) storing the configuration values on the environment. Because this way the 53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) environment ends up acting as central configuration storage the 54b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) attributes may clash which is why extensions have to ensure that the names 55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) they choose for configuration are not too generic. ``prefix`` for example 56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) is a terrible name, ``fragment_cache_prefix`` on the other hand is a good 57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) name as includes the name of the extension (fragment cache). 58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) #: if this extension parses this is the list of tags it's listening to. 61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tags = set() 62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) #: the priority of that extension. This is especially useful for 64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) #: extensions that preprocess values. A lower value means higher 65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) #: priority. 66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) #: 67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) #: .. versionadded:: 2.4 68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) priority = 100 69b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __init__(self, environment): 71b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.environment = environment 72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def bind(self, environment): 74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Create a copy of this extension bound to another environment.""" 75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv = object.__new__(self.__class__) 76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv.__dict__.update(self.__dict__) 77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv.environment = environment 78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return rv 79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def preprocess(self, source, name, filename=None): 81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """This method is called before the actual lexing and can be used to 82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) preprocess the source. The `filename` is optional. The return value 83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) must be the preprocessed source. 84b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return source 86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def filter_stream(self, stream): 88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """It's passed a :class:`~jinja2.lexer.TokenStream` that can be used 89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) to filter tokens returned. This method has to return an iterable of 90b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :class:`~jinja2.lexer.Token`\s, but it doesn't have to return a 91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :class:`~jinja2.lexer.TokenStream`. 92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) In the `ext` folder of the Jinja2 source distribution there is a file 94b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) called `inlinegettext.py` which implements a filter that utilizes this 95b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) method. 96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return stream 98b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def parse(self, parser): 100b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """If any of the :attr:`tags` matched this method is called with the 101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser as first argument. The token the parser stream is pointing at 102b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) is the name token that matched. This method has to return one or a 103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) list of multiple nodes. 104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) raise NotImplementedError() 106b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def attr(self, name, lineno=None): 108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Return an attribute node for the current extension. This is useful 109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) to pass constants on extensions to generated template code. 110b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :: 112b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 113b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.attr('_my_attribute', lineno=lineno) 114b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 115b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno) 116b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 117b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def call_method(self, name, args=None, kwargs=None, dyn_args=None, 118b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) dyn_kwargs=None, lineno=None): 119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Call a method of the extension. This is a shortcut for 120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :meth:`attr` + :class:`jinja2.nodes.Call`. 121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if args is None: 123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) args = [] 124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if kwargs is None: 125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) kwargs = [] 126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return nodes.Call(self.attr(name, lineno=lineno), args, kwargs, 127b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) dyn_args, dyn_kwargs, lineno=lineno) 128b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 129b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 130b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)@contextfunction 131b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def _gettext_alias(__context, *args, **kwargs): 132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return __context.call(__context.resolve('gettext'), *args, **kwargs) 133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 134b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 135b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def _make_new_gettext(func): 136b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @contextfunction 137b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def gettext(__context, __string, **variables): 138b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv = __context.call(func, __string) 139b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if __context.eval_ctx.autoescape: 140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv = Markup(rv) 141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return rv % variables 142b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return gettext 143b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 145b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def _make_new_ngettext(func): 146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @contextfunction 147b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def ngettext(__context, __singular, __plural, __num, **variables): 148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) variables.setdefault('num', __num) 149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv = __context.call(func, __singular, __plural, __num) 150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if __context.eval_ctx.autoescape: 151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) rv = Markup(rv) 152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return rv % variables 153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return ngettext 154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class InternationalizationExtension(Extension): 157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """This extension adds gettext support to Jinja2.""" 158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tags = set(['trans']) 159b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # TODO: the i18n extension is currently reevaluating values in a few 161b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # situations. Take this example: 162b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # {% trans count=something() %}{{ count }} foo{% pluralize 163b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # %}{{ count }} fooss{% endtrans %} 164b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # something is called twice here. One time for the gettext value and 165b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # the other time for the n-parameter of the ngettext function. 166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __init__(self, environment): 168b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) Extension.__init__(self, environment) 169b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) environment.globals['_'] = _gettext_alias 170b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) environment.extend( 171b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) install_gettext_translations=self._install, 172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) install_null_translations=self._install_null, 173b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) install_gettext_callables=self._install_callables, 174b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) uninstall_gettext_translations=self._uninstall, 175b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) extract_translations=self._extract, 176b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) newstyle_gettext=False 177b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ) 178b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 179b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def _install(self, translations, newstyle=None): 180b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) gettext = getattr(translations, 'ugettext', None) 181b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if gettext is None: 182b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) gettext = translations.gettext 183b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ngettext = getattr(translations, 'ungettext', None) 184b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if ngettext is None: 185b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ngettext = translations.ngettext 186b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self._install_callables(gettext, ngettext, newstyle) 187b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 188b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def _install_null(self, newstyle=None): 189b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self._install_callables( 190b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) lambda x: x, 191b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) lambda s, p, n: (n != 1 and (p,) or (s,))[0], 192b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) newstyle 193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ) 194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def _install_callables(self, gettext, ngettext, newstyle=None): 196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if newstyle is not None: 197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.environment.newstyle_gettext = newstyle 198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if self.environment.newstyle_gettext: 199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) gettext = _make_new_gettext(gettext) 200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ngettext = _make_new_ngettext(ngettext) 201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.environment.globals.update( 202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) gettext=gettext, 203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ngettext=ngettext 204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ) 205b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 206b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def _uninstall(self, translations): 207b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for key in 'gettext', 'ngettext': 208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.environment.globals.pop(key, None) 209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS): 21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if isinstance(source, string_types): 212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) source = self.environment.parse(source) 213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return extract_from_ast(source, gettext_functions) 214b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 215b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def parse(self, parser): 216b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Parse a translatable tag.""" 217b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) lineno = next(parser.stream).lineno 218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) num_called_num = False 219b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 220b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # find all the variables referenced. Additionally a variable can be 221b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # defined in the body of the trans block too, but this is checked at 222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # a later state. 223b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) plural_expr = None 22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) plural_expr_assignment = None 225b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) variables = {} 226b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) while parser.stream.current.type != 'block_end': 227b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if variables: 228b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.stream.expect('comma') 229b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 230b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # skip colon for python compatibility 231b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if parser.stream.skip_if('colon'): 232b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) break 233b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 234b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) name = parser.stream.expect('name') 235b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if name.value in variables: 236b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.fail('translatable variable %r defined twice.' % 237b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) name.value, name.lineno, 238b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exc=TemplateAssertionError) 239b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # expressions 241b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if parser.stream.current.type == 'assign': 242b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next(parser.stream) 243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) variables[name.value] = var = parser.parse_expression() 244b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 245b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) variables[name.value] = var = nodes.Name(name.value, 'load') 246b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 247b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if plural_expr is None: 24858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if isinstance(var, nodes.Call): 24958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) plural_expr = nodes.Name('_trans', 'load') 25058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) variables[name.value] = plural_expr 25158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) plural_expr_assignment = nodes.Assign( 25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) nodes.Name('_trans', 'store'), var) 25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) else: 25458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) plural_expr = var 255b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) num_called_num = name.value == 'num' 256b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 257b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.stream.expect('block_end') 258b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 259b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) plural = plural_names = None 260b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) have_plural = False 261b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) referenced = set() 262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 263b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # now parse until endtrans or pluralize 264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) singular_names, singular = self._parse_block(parser, True) 265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if singular_names: 266b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) referenced.update(singular_names) 267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if plural_expr is None: 268b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) plural_expr = nodes.Name(singular_names[0], 'load') 269b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) num_called_num = singular_names[0] == 'num' 270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 271b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # if we have a pluralize block, we parse that too 272b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if parser.stream.current.test('name:pluralize'): 273b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) have_plural = True 274b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next(parser.stream) 275b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if parser.stream.current.type != 'block_end': 276b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) name = parser.stream.expect('name') 277b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if name.value not in variables: 278b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.fail('unknown variable %r for pluralization' % 279b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) name.value, name.lineno, 280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exc=TemplateAssertionError) 281b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) plural_expr = variables[name.value] 282b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) num_called_num = name.value == 'num' 283b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.stream.expect('block_end') 284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) plural_names, plural = self._parse_block(parser, False) 285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next(parser.stream) 286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) referenced.update(plural_names) 287b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 288b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next(parser.stream) 289b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # register free names as simple name expressions 291b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for var in referenced: 292b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if var not in variables: 293b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) variables[var] = nodes.Name(var, 'load') 294b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 295b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not have_plural: 296b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) plural_expr = None 297b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) elif plural_expr is None: 298b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.fail('pluralize without variables', lineno) 299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 300b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = self._make_node(singular, plural, variables, plural_expr, 301b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) bool(referenced), 302b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) num_called_num and have_plural) 303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node.set_lineno(lineno) 30458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if plural_expr_assignment is not None: 30558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return [plural_expr_assignment, node] 30658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) else: 30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return node 308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def _parse_block(self, parser, allow_pluralize): 310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Parse until the next block tag with a given name.""" 311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) referenced = [] 312b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buf = [] 313b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) while 1: 314b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if parser.stream.current.type == 'data': 315b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buf.append(parser.stream.current.value.replace('%', '%%')) 316b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next(parser.stream) 317b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) elif parser.stream.current.type == 'variable_begin': 318b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next(parser.stream) 319b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) name = parser.stream.expect('name').value 320b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) referenced.append(name) 321b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buf.append('%%(%s)s' % name) 322b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.stream.expect('variable_end') 323b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) elif parser.stream.current.type == 'block_begin': 324b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next(parser.stream) 325b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if parser.stream.current.test('name:endtrans'): 326b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) break 327b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) elif parser.stream.current.test('name:pluralize'): 328b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if allow_pluralize: 329b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) break 330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.fail('a translatable section can have only one ' 331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 'pluralize section') 332b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.fail('control structures in translatable sections are ' 333b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 'not allowed') 334b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) elif parser.stream.eos: 335b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.fail('unclosed translation block') 336b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 337b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) assert False, 'internal parser error' 338b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 339b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return referenced, concat(buf) 340b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 341b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def _make_node(self, singular, plural, variables, plural_expr, 342b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) vars_referenced, num_called_num): 343b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Generates a useful node from the data provided.""" 344b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # no variables referenced? no need to escape for old style 345b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # gettext invocations only if there are vars. 346b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not vars_referenced and not self.environment.newstyle_gettext: 347b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) singular = singular.replace('%%', '%') 348b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if plural: 349b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) plural = plural.replace('%%', '%') 350b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 351b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # singular only: 352b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if plural_expr is None: 353b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) gettext = nodes.Name('gettext', 'load') 354b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = nodes.Call(gettext, [nodes.Const(singular)], 355b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) [], None, None) 356b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 357b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # singular and plural 358b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 359b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ngettext = nodes.Name('ngettext', 'load') 360b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = nodes.Call(ngettext, [ 361b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) nodes.Const(singular), 362b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) nodes.Const(plural), 363b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) plural_expr 364b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ], [], None, None) 365b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 366b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # in case newstyle gettext is used, the method is powerful 367b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # enough to handle the variable expansion and autoescape 368b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # handling itself 369b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if self.environment.newstyle_gettext: 37058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for key, value in iteritems(variables): 371b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # the function adds that later anyways in case num was 372b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # called num, so just skip it. 373b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if num_called_num and key == 'num': 374b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) continue 375b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node.kwargs.append(nodes.Keyword(key, value)) 376b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 377b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # otherwise do that here 378b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 379b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # mark the return value as safe if we are in an 380b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # environment with autoescaping turned on 381b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = nodes.MarkSafeIfAutoescape(node) 382b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if variables: 383b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = nodes.Mod(node, nodes.Dict([ 384b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) nodes.Pair(nodes.Const(key), value) 385b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for key, value in variables.items() 386b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ])) 387b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return nodes.Output([node]) 388b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 389b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 390b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class ExprStmtExtension(Extension): 391b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Adds a `do` tag to Jinja2 that works like the print statement just 392b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) that it doesn't print the return value. 393b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 394b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tags = set(['do']) 395b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 396b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def parse(self, parser): 397b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = nodes.ExprStmt(lineno=next(parser.stream).lineno) 398b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node.node = parser.parse_tuple() 399b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return node 400b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 401b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 402b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class LoopControlExtension(Extension): 403b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Adds break and continue to the template engine.""" 404b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tags = set(['break', 'continue']) 405b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 406b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def parse(self, parser): 407b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) token = next(parser.stream) 408b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if token.value == 'break': 409b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return nodes.Break(lineno=token.lineno) 410b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return nodes.Continue(lineno=token.lineno) 411b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 412b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 413b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class WithExtension(Extension): 414b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Adds support for a django-like with block.""" 415b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tags = set(['with']) 416b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 417b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def parse(self, parser): 418b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = nodes.Scope(lineno=next(parser.stream).lineno) 419b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) assignments = [] 420b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) while parser.stream.current.type != 'block_end': 421b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) lineno = parser.stream.current.lineno 422b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if assignments: 423b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.stream.expect('comma') 424b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) target = parser.parse_assign_target() 425b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parser.stream.expect('assign') 426b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) expr = parser.parse_expression() 427b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) assignments.append(nodes.Assign(target, expr, lineno=lineno)) 428b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node.body = assignments + \ 429b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) list(parser.parse_statements(('name:endwith',), 430b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) drop_needle=True)) 431b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return node 432b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 433b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 434b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class AutoEscapeExtension(Extension): 435b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Changes auto escape rules for a scope.""" 436b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tags = set(['autoescape']) 437b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 438b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def parse(self, parser): 439b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = nodes.ScopedEvalContextModifier(lineno=next(parser.stream).lineno) 440b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node.options = [ 441b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) nodes.Keyword('autoescape', parser.parse_expression()) 442b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ] 443b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node.body = parser.parse_statements(('name:endautoescape',), 444b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) drop_needle=True) 445b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return nodes.Scope([node]) 446b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 447b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 448b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS, 449b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) babel_style=True): 450b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Extract localizable strings from the given template node. Per 451b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) default this function returns matches in babel style that means non string 452b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) parameters as well as keyword arguments are returned as `None`. This 453b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) allows Babel to figure out what you really meant if you are using 454b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) gettext functions that allow keyword arguments for placeholder expansion. 455b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) If you don't want that behavior set the `babel_style` parameter to `False` 456b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) which causes only strings to be returned and parameters are always stored 457b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) in tuples. As a consequence invalid gettext calls (calls without a single 458b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) string parameter or string parameters after non-string parameters) are 459b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) skipped. 460b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 461b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) This example explains the behavior: 462b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 463b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) >>> from jinja2 import Environment 464b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) >>> env = Environment() 465b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) >>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}') 466b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) >>> list(extract_from_ast(node)) 467b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) [(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))] 468b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) >>> list(extract_from_ast(node, babel_style=False)) 469b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) [(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))] 470b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 471b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) For every string found this function yields a ``(lineno, function, 472b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) message)`` tuple, where: 473b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 474b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) * ``lineno`` is the number of the line on which the string was found, 475b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) * ``function`` is the name of the ``gettext`` function used (if the 476b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) string was extracted from embedded Python code), and 477b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) * ``message`` is the string itself (a ``unicode`` object, or a tuple 478b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) of ``unicode`` objects for functions with multiple string arguments). 479b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 480b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) This extraction function operates on the AST and is because of that unable 481b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) to extract any comments. For comment support you have to use the babel 482b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) extraction interface or extract comments yourself. 483b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 484b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for node in node.find_all(nodes.Call): 485b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not isinstance(node.node, nodes.Name) or \ 486b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node.node.name not in gettext_functions: 487b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) continue 488b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 489b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings = [] 490b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for arg in node.args: 491b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if isinstance(arg, nodes.Const) and \ 49258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) isinstance(arg.value, string_types): 493b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings.append(arg.value) 494b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 495b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings.append(None) 496b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 497b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for arg in node.kwargs: 498b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings.append(None) 499b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if node.dyn_args is not None: 500b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings.append(None) 501b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if node.dyn_kwargs is not None: 502b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings.append(None) 503b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 504b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not babel_style: 505b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings = tuple(x for x in strings if x is not None) 506b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not strings: 507b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) continue 508b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 509b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if len(strings) == 1: 510b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings = strings[0] 511b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 512b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) strings = tuple(strings) 513b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) yield node.lineno, node.node.name, strings 514b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 515b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 516b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class _CommentFinder(object): 517b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Helper class to find comments in a token stream. Can only 518b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) find comments for gettext calls forwards. Once the comment 519b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) from line 4 is found, a comment for line 1 will not return a 520b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) usable value. 521b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 522b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 523b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __init__(self, tokens, comment_tags): 524b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.tokens = tokens 525b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.comment_tags = comment_tags 526b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.offset = 0 527b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.last_lineno = 0 528b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 529b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def find_backwards(self, offset): 530b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try: 531b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for _, token_type, token_value in \ 532b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) reversed(self.tokens[self.offset:offset]): 533b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if token_type in ('comment', 'linecomment'): 534b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try: 535b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) prefix, comment = token_value.split(None, 1) 536b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) except ValueError: 537b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) continue 538b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if prefix in self.comment_tags: 539b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return [comment.rstrip()] 540b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return [] 541b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) finally: 542b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.offset = offset 543b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 544b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def find_comments(self, lineno): 545b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not self.comment_tags or self.last_lineno > lineno: 546b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return [] 547b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset:]): 548b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if token_lineno > lineno: 549b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return self.find_backwards(self.offset + idx) 550b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return self.find_backwards(len(self.tokens)) 551b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 552b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 553b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def babel_extract(fileobj, keywords, comment_tags, options): 554b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Babel extraction method for Jinja templates. 555b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 556b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) .. versionchanged:: 2.3 557b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) Basic support for translation comments was added. If `comment_tags` 558b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) is now set to a list of keywords for extraction, the extractor will 559b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try to find the best preceeding comment that begins with one of the 560b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) keywords. For best results, make sure to not have more than one 561b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) gettext call in one line of code and the matching comment in the 562b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) same line or the line before. 563b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 564b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) .. versionchanged:: 2.5.1 565b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) The `newstyle_gettext` flag can be set to `True` to enable newstyle 566b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) gettext calls. 567b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 56858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) .. versionchanged:: 2.7 56958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) A `silent` option can now be provided. If set to `False` template 57058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) syntax errors are propagated instead of being ignored. 57158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 572b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :param fileobj: the file-like object the messages should be extracted from 573b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :param keywords: a list of keywords (i.e. function names) that should be 574b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) recognized as translation functions 575b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :param comment_tags: a list of translator tags to search for and include 576b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) in the results. 577b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :param options: a dictionary of additional options (optional) 578b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :return: an iterator over ``(lineno, funcname, message, comments)`` tuples. 579b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) (comments will be empty currently) 580b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 581b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) extensions = set() 582b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for extension in options.get('extensions', '').split(','): 583b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) extension = extension.strip() 584b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not extension: 585b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) continue 586b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) extensions.add(import_string(extension)) 587b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if InternationalizationExtension not in extensions: 588b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) extensions.add(InternationalizationExtension) 589b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 590b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def getbool(options, key, default=False): 59158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return options.get(key, str(default)).lower() in \ 59258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ('1', 'on', 'yes', 'true') 593b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 59458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) silent = getbool(options, 'silent', True) 595b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) environment = Environment( 596b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) options.get('block_start_string', BLOCK_START_STRING), 597b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) options.get('block_end_string', BLOCK_END_STRING), 598b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) options.get('variable_start_string', VARIABLE_START_STRING), 599b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) options.get('variable_end_string', VARIABLE_END_STRING), 600b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) options.get('comment_start_string', COMMENT_START_STRING), 601b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) options.get('comment_end_string', COMMENT_END_STRING), 602b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) options.get('line_statement_prefix') or LINE_STATEMENT_PREFIX, 603b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) options.get('line_comment_prefix') or LINE_COMMENT_PREFIX, 604b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) getbool(options, 'trim_blocks', TRIM_BLOCKS), 60558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) getbool(options, 'lstrip_blocks', LSTRIP_BLOCKS), 60658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) NEWLINE_SEQUENCE, 60758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) getbool(options, 'keep_trailing_newline', KEEP_TRAILING_NEWLINE), 60858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) frozenset(extensions), 609b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) cache_size=0, 610b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) auto_reload=False 611b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ) 612b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 613b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if getbool(options, 'newstyle_gettext'): 614b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) environment.newstyle_gettext = True 615b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 616b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) source = fileobj.read().decode(options.get('encoding', 'utf-8')) 617b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try: 618b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) node = environment.parse(source) 619b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tokens = list(environment.lex(environment.preprocess(source))) 62058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) except TemplateSyntaxError as e: 62158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if not silent: 62258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) raise 623b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # skip templates with syntax errors 624b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return 625b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 626b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) finder = _CommentFinder(tokens, comment_tags) 627b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for lineno, func, message in extract_from_ast(node, keywords): 628b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) yield lineno, func, message, finder.find_comments(lineno) 629b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 630b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 631b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#: nicer import names 632b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)i18n = InternationalizationExtension 633b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)do = ExprStmtExtension 634b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)loopcontrols = LoopControlExtension 635b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)with_ = WithExtension 636b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)autoescape = AutoEscapeExtension 637