def do_xmlattr(_eval_ctx, d, autospace=True): """Create an SGML/XML attribute string based on the items in a dict. All values that are neither `none` nor `undefined` are automatically escaped: .. sourcecode:: html+jinja <ul{{ {'class': 'my_list', 'missing': none, 'id': 'list-%d'|format(variable)}|xmlattr }}> ... </ul> Results in something like this: .. sourcecode:: html <ul class="my_list" id="list-42"> ... </ul> As you can see it automatically prepends a space in front of the item if the filter returned something unless the second parameter is false. """ rv = u' '.join( u'%s="%s"' % (escape(key), escape(value)) for key, value in iteritems(d) if value is not None and not isinstance(value, Undefined) ) if autospace and rv: rv = u' ' + rv if _eval_ctx.autoescape: rv = Markup(rv) return rv
def branch_update(self, branch_symbols): stores = {} for branch in branch_symbols: for target in branch.stores: if target in self.stores: continue stores[target] = stores.get(target, 0) + 1 for sym in branch_symbols: self.refs.update(sym.refs) self.loads.update(sym.loads) self.stores.update(sym.stores) for name, branch_count in iteritems(stores): if branch_count == len(branch_symbols): continue target = self.find_ref(name) assert target is not None, 'should not happen' if self.parent is not None: outer_target = self.parent.find_ref(name) if outer_target is not None: self.loads[target] = (VAR_LOAD_ALIAS, outer_target) continue self.loads[target] = (VAR_LOAD_RESOLVE, name)
def dump_param_targets(self): rv = set() node = self while node is not None: for target, (instr, _) in iteritems(self.loads): if instr == VAR_LOAD_PARAMETER: rv.add(target) node = node.parent return rv
def derived(self, locals=None): """Internal helper function to create a derived context. This is used in situations where the system needs a new context in the same template that is independent. """ context = new_context(self.environment, self.name, {}, self.get_all(), True, None, locals) context.eval_ctx = self.eval_ctx context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) return context
def _make_node(self, singular, plural, variables, plural_expr, vars_referenced, num_called_num): """Generates a useful node from the data provided.""" # no variables referenced? no need to escape for old style # gettext invocations only if there are vars. if not vars_referenced and not self.environment.newstyle_gettext: singular = singular.replace('%%', '%') if plural: plural = plural.replace('%%', '%') # singular only: if plural_expr is None: gettext = nodes.Name('gettext', 'load') node = nodes.Call(gettext, [nodes.Const(singular)], [], None, None) # singular and plural else: ngettext = nodes.Name('ngettext', 'load') node = nodes.Call( ngettext, [nodes.Const(singular), nodes.Const(plural), plural_expr], [], None, None) # in case newstyle gettext is used, the method is powerful # enough to handle the variable expansion and autoescape # handling itself if self.environment.newstyle_gettext: for key, value in iteritems(variables): # the function adds that later anyways in case num was # called num, so just skip it. if num_called_num and key == 'num': continue node.kwargs.append(nodes.Keyword(key, value)) # otherwise do that here else: # mark the return value as safe if we are in an # environment with autoescaping turned on node = nodes.MarkSafeIfAutoescape(node) if variables: node = nodes.Mod( node, nodes.Dict([ nodes.Pair(nodes.Const(key), value) for key, value in variables.items() ])) return nodes.Output([node])
def __init__(self, environment, parent, name, blocks): self.parent = parent self.vars = {} self.environment = environment self.eval_ctx = EvalContext(self.environment, name) self.exported_vars = set() self.name = name # create the initial mapping of blocks. Whenever template inheritance # takes place the runtime will update this mapping with the new blocks # from the template. self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) # In case we detect the fast resolve mode we can set up an alias # here that bypasses the legacy code logic. if self._fast_resolve_mode: self.resolve_or_missing = MethodType(resolve_or_missing, self)
def do_urlencode(value): """Escape strings for use in URLs (uses UTF-8 encoding). It accepts both dictionaries and regular strings as well as pairwise iterables. .. versionadded:: 2.7 """ itemiter = None if isinstance(value, dict): itemiter = iteritems(value) elif not isinstance(value, string_types): try: itemiter = iter(value) except TypeError: pass if itemiter is None: return unicode_urlencode(value) return u'&'.join(unicode_urlencode(k) + '=' + unicode_urlencode(v, for_qs=True) for k, v in itemiter)
def new_context(environment, template_name, blocks, vars=None, shared=None, globals=None, locals=None): """Internal helper to for context creation.""" if vars is None: vars = {} if shared: parent = vars else: parent = dict(globals or (), **vars) if locals: # if the parent is shared a copy should be created because # we don't want to modify the dict passed if shared: parent = dict(parent) for key, value in iteritems(locals): if value is not missing: parent[key] = value return environment.context_class(environment, parent, template_name, blocks)
def enter_frame(self, frame): """Remember all undeclared identifiers.""" CodeGenerator.enter_frame(self, frame) for _, (action, param) in iteritems(frame.symbols.loads): if action == 'resolve': self.undeclared_identifiers.add(param)
def list_templates(self): result = [] for prefix, loader in iteritems(self.mapping): for template in loader.list_templates(): result.append(prefix + self.delimiter + template) return result
def tokeniter(self, source, name, filename=None, state=None): """This method tokenizes the text and returns the tokens in a generator. Use this method if you just want to tokenize a template. """ source = text_type(source) lines = source.splitlines() if self.keep_trailing_newline and source: for newline in ('\r\n', '\r', '\n'): if source.endswith(newline): lines.append('') break source = '\n'.join(lines) pos = 0 lineno = 1 stack = ['root'] if state is not None and state != 'root': assert state in ('variable', 'block'), 'invalid state' stack.append(state + '_begin') else: state = 'root' statetokens = self.rules[stack[-1]] source_length = len(source) balancing_stack = [] while 1: # tokenizer loop for regex, tokens, new_state in statetokens: m = regex.match(source, pos) # if no match we try again with the next rule if m is None: continue # we only match blocks and variables if braces / parentheses # are balanced. continue parsing with the lower rule which # is the operator rule. do this only if the end tags look # like operators if balancing_stack and \ tokens in ('variable_end', 'block_end', 'linestatement_end'): continue # tuples support more options if isinstance(tokens, tuple): for idx, token in enumerate(tokens): # failure group if token.__class__ is Failure: raise token(lineno, filename) # bygroup is a bit more complex, in that case we # yield for the current token the first named # group that matched elif token == '#bygroup': for key, value in iteritems(m.groupdict()): if value is not None: yield lineno, key, value lineno += value.count('\n') break else: raise RuntimeError('%r wanted to resolve ' 'the token dynamically' ' but no group matched' % regex) # normal group else: data = m.group(idx + 1) if data or token not in ignore_if_empty: yield lineno, token, data lineno += data.count('\n') # strings as token just are yielded as it. else: data = m.group() # update brace/parentheses balance if tokens == 'operator': if data == '{': balancing_stack.append('}') elif data == '(': balancing_stack.append(')') elif data == '[': balancing_stack.append(']') elif data in ('}', ')', ']'): if not balancing_stack: raise TemplateSyntaxError( 'unexpected \'%s\'' % data, lineno, name, filename) expected_op = balancing_stack.pop() if expected_op != data: raise TemplateSyntaxError( 'unexpected \'%s\', ' 'expected \'%s\'' % (data, expected_op), lineno, name, filename) # yield items if data or tokens not in ignore_if_empty: yield lineno, tokens, data lineno += data.count('\n') # fetch new position into new variable so that we can check # if there is a internal parsing error which would result # in an infinite loop pos2 = m.end() # handle state changes if new_state is not None: # remove the uppermost state if new_state == '#pop': stack.pop() # resolve the new state by group checking elif new_state == '#bygroup': for key, value in iteritems(m.groupdict()): if value is not None: stack.append(key) break else: raise RuntimeError('%r wanted to resolve the ' 'new state dynamically but' ' no group matched' % regex) # direct state name given else: stack.append(new_state) statetokens = self.rules[stack[-1]] # we are still at the same position and no stack change. # this means a loop without break condition, avoid that and # raise error elif pos2 == pos: raise RuntimeError('%r yielded empty string without ' 'stack change' % regex) # publish new function and start again pos = pos2 break # if loop terminated without break we haven't found a single match # either we are at the end of the file or we have a problem else: # end of text if pos >= source_length: return # something went wrong raise TemplateSyntaxError( 'unexpected char %r at %d' % (source[pos], pos), lineno, name, filename)
'}': TOKEN_RBRACE, '==': TOKEN_EQ, '!=': TOKEN_NE, '>': TOKEN_GT, '>=': TOKEN_GTEQ, '<': TOKEN_LT, '<=': TOKEN_LTEQ, '=': TOKEN_ASSIGN, '.': TOKEN_DOT, ':': TOKEN_COLON, '|': TOKEN_PIPE, ',': TOKEN_COMMA, ';': TOKEN_SEMICOLON } reverse_operators = dict([(v, k) for k, v in iteritems(operators)]) assert len(operators) == len(reverse_operators), 'operators dropped' operator_re = re.compile( '(%s)' % '|'.join(re.escape(x) for x in sorted(operators, key=lambda x: -len(x)))) ignored_tokens = frozenset([ TOKEN_COMMENT_BEGIN, TOKEN_COMMENT, TOKEN_COMMENT_END, TOKEN_WHITESPACE, TOKEN_LINECOMMENT_BEGIN, TOKEN_LINECOMMENT_END, TOKEN_LINECOMMENT ]) ignore_if_empty = frozenset( [TOKEN_WHITESPACE, TOKEN_DATA, TOKEN_COMMENT, TOKEN_LINECOMMENT]) def _describe_token_type(token_type): if token_type in reverse_operators: