1*635a8641SAndroid Build Coastguard Worker# -*- coding: utf-8 -*- 2*635a8641SAndroid Build Coastguard Worker""" 3*635a8641SAndroid Build Coastguard Worker jinja2.runtime 4*635a8641SAndroid Build Coastguard Worker ~~~~~~~~~~~~~~ 5*635a8641SAndroid Build Coastguard Worker 6*635a8641SAndroid Build Coastguard Worker Runtime helpers. 7*635a8641SAndroid Build Coastguard Worker 8*635a8641SAndroid Build Coastguard Worker :copyright: (c) 2017 by the Jinja Team. 9*635a8641SAndroid Build Coastguard Worker :license: BSD. 10*635a8641SAndroid Build Coastguard Worker""" 11*635a8641SAndroid Build Coastguard Workerimport sys 12*635a8641SAndroid Build Coastguard Worker 13*635a8641SAndroid Build Coastguard Workerfrom itertools import chain 14*635a8641SAndroid Build Coastguard Workerfrom types import MethodType 15*635a8641SAndroid Build Coastguard Worker 16*635a8641SAndroid Build Coastguard Workerfrom jinja2.nodes import EvalContext, _context_function_types 17*635a8641SAndroid Build Coastguard Workerfrom jinja2.utils import Markup, soft_unicode, escape, missing, concat, \ 18*635a8641SAndroid Build Coastguard Worker internalcode, object_type_repr, evalcontextfunction, Namespace 19*635a8641SAndroid Build Coastguard Workerfrom jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ 20*635a8641SAndroid Build Coastguard Worker TemplateNotFound 21*635a8641SAndroid Build Coastguard Workerfrom jinja2._compat import imap, text_type, iteritems, \ 22*635a8641SAndroid Build Coastguard Worker implements_iterator, implements_to_string, string_types, PY2, \ 23*635a8641SAndroid Build Coastguard Worker with_metaclass 24*635a8641SAndroid Build Coastguard Worker 25*635a8641SAndroid Build Coastguard Worker 26*635a8641SAndroid Build Coastguard Worker# these variables are exported to the template runtime 27*635a8641SAndroid Build Coastguard Worker__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup', 28*635a8641SAndroid Build Coastguard Worker 'TemplateRuntimeError', 'missing', 'concat', 'escape', 29*635a8641SAndroid Build Coastguard Worker 'markup_join', 'unicode_join', 'to_string', 'identity', 30*635a8641SAndroid Build Coastguard Worker 'TemplateNotFound', 'Namespace'] 31*635a8641SAndroid Build Coastguard Worker 32*635a8641SAndroid Build Coastguard Worker#: the name of the function that is used to convert something into 33*635a8641SAndroid Build Coastguard Worker#: a string. We can just use the text type here. 34*635a8641SAndroid Build Coastguard Workerto_string = text_type 35*635a8641SAndroid Build Coastguard Worker 36*635a8641SAndroid Build Coastguard Worker#: the identity function. Useful for certain things in the environment 37*635a8641SAndroid Build Coastguard Workeridentity = lambda x: x 38*635a8641SAndroid Build Coastguard Worker 39*635a8641SAndroid Build Coastguard Worker_first_iteration = object() 40*635a8641SAndroid Build Coastguard Worker_last_iteration = object() 41*635a8641SAndroid Build Coastguard Worker 42*635a8641SAndroid Build Coastguard Worker 43*635a8641SAndroid Build Coastguard Workerdef markup_join(seq): 44*635a8641SAndroid Build Coastguard Worker """Concatenation that escapes if necessary and converts to unicode.""" 45*635a8641SAndroid Build Coastguard Worker buf = [] 46*635a8641SAndroid Build Coastguard Worker iterator = imap(soft_unicode, seq) 47*635a8641SAndroid Build Coastguard Worker for arg in iterator: 48*635a8641SAndroid Build Coastguard Worker buf.append(arg) 49*635a8641SAndroid Build Coastguard Worker if hasattr(arg, '__html__'): 50*635a8641SAndroid Build Coastguard Worker return Markup(u'').join(chain(buf, iterator)) 51*635a8641SAndroid Build Coastguard Worker return concat(buf) 52*635a8641SAndroid Build Coastguard Worker 53*635a8641SAndroid Build Coastguard Worker 54*635a8641SAndroid Build Coastguard Workerdef unicode_join(seq): 55*635a8641SAndroid Build Coastguard Worker """Simple args to unicode conversion and concatenation.""" 56*635a8641SAndroid Build Coastguard Worker return concat(imap(text_type, seq)) 57*635a8641SAndroid Build Coastguard Worker 58*635a8641SAndroid Build Coastguard Worker 59*635a8641SAndroid Build Coastguard Workerdef new_context(environment, template_name, blocks, vars=None, 60*635a8641SAndroid Build Coastguard Worker shared=None, globals=None, locals=None): 61*635a8641SAndroid Build Coastguard Worker """Internal helper to for context creation.""" 62*635a8641SAndroid Build Coastguard Worker if vars is None: 63*635a8641SAndroid Build Coastguard Worker vars = {} 64*635a8641SAndroid Build Coastguard Worker if shared: 65*635a8641SAndroid Build Coastguard Worker parent = vars 66*635a8641SAndroid Build Coastguard Worker else: 67*635a8641SAndroid Build Coastguard Worker parent = dict(globals or (), **vars) 68*635a8641SAndroid Build Coastguard Worker if locals: 69*635a8641SAndroid Build Coastguard Worker # if the parent is shared a copy should be created because 70*635a8641SAndroid Build Coastguard Worker # we don't want to modify the dict passed 71*635a8641SAndroid Build Coastguard Worker if shared: 72*635a8641SAndroid Build Coastguard Worker parent = dict(parent) 73*635a8641SAndroid Build Coastguard Worker for key, value in iteritems(locals): 74*635a8641SAndroid Build Coastguard Worker if value is not missing: 75*635a8641SAndroid Build Coastguard Worker parent[key] = value 76*635a8641SAndroid Build Coastguard Worker return environment.context_class(environment, parent, template_name, 77*635a8641SAndroid Build Coastguard Worker blocks) 78*635a8641SAndroid Build Coastguard Worker 79*635a8641SAndroid Build Coastguard Worker 80*635a8641SAndroid Build Coastguard Workerclass TemplateReference(object): 81*635a8641SAndroid Build Coastguard Worker """The `self` in templates.""" 82*635a8641SAndroid Build Coastguard Worker 83*635a8641SAndroid Build Coastguard Worker def __init__(self, context): 84*635a8641SAndroid Build Coastguard Worker self.__context = context 85*635a8641SAndroid Build Coastguard Worker 86*635a8641SAndroid Build Coastguard Worker def __getitem__(self, name): 87*635a8641SAndroid Build Coastguard Worker blocks = self.__context.blocks[name] 88*635a8641SAndroid Build Coastguard Worker return BlockReference(name, self.__context, blocks, 0) 89*635a8641SAndroid Build Coastguard Worker 90*635a8641SAndroid Build Coastguard Worker def __repr__(self): 91*635a8641SAndroid Build Coastguard Worker return '<%s %r>' % ( 92*635a8641SAndroid Build Coastguard Worker self.__class__.__name__, 93*635a8641SAndroid Build Coastguard Worker self.__context.name 94*635a8641SAndroid Build Coastguard Worker ) 95*635a8641SAndroid Build Coastguard Worker 96*635a8641SAndroid Build Coastguard Worker 97*635a8641SAndroid Build Coastguard Workerdef _get_func(x): 98*635a8641SAndroid Build Coastguard Worker return getattr(x, '__func__', x) 99*635a8641SAndroid Build Coastguard Worker 100*635a8641SAndroid Build Coastguard Worker 101*635a8641SAndroid Build Coastguard Workerclass ContextMeta(type): 102*635a8641SAndroid Build Coastguard Worker 103*635a8641SAndroid Build Coastguard Worker def __new__(cls, name, bases, d): 104*635a8641SAndroid Build Coastguard Worker rv = type.__new__(cls, name, bases, d) 105*635a8641SAndroid Build Coastguard Worker if bases == (): 106*635a8641SAndroid Build Coastguard Worker return rv 107*635a8641SAndroid Build Coastguard Worker 108*635a8641SAndroid Build Coastguard Worker resolve = _get_func(rv.resolve) 109*635a8641SAndroid Build Coastguard Worker default_resolve = _get_func(Context.resolve) 110*635a8641SAndroid Build Coastguard Worker resolve_or_missing = _get_func(rv.resolve_or_missing) 111*635a8641SAndroid Build Coastguard Worker default_resolve_or_missing = _get_func(Context.resolve_or_missing) 112*635a8641SAndroid Build Coastguard Worker 113*635a8641SAndroid Build Coastguard Worker # If we have a changed resolve but no changed default or missing 114*635a8641SAndroid Build Coastguard Worker # resolve we invert the call logic. 115*635a8641SAndroid Build Coastguard Worker if resolve is not default_resolve and \ 116*635a8641SAndroid Build Coastguard Worker resolve_or_missing is default_resolve_or_missing: 117*635a8641SAndroid Build Coastguard Worker rv._legacy_resolve_mode = True 118*635a8641SAndroid Build Coastguard Worker elif resolve is default_resolve and \ 119*635a8641SAndroid Build Coastguard Worker resolve_or_missing is default_resolve_or_missing: 120*635a8641SAndroid Build Coastguard Worker rv._fast_resolve_mode = True 121*635a8641SAndroid Build Coastguard Worker 122*635a8641SAndroid Build Coastguard Worker return rv 123*635a8641SAndroid Build Coastguard Worker 124*635a8641SAndroid Build Coastguard Worker 125*635a8641SAndroid Build Coastguard Workerdef resolve_or_missing(context, key, missing=missing): 126*635a8641SAndroid Build Coastguard Worker if key in context.vars: 127*635a8641SAndroid Build Coastguard Worker return context.vars[key] 128*635a8641SAndroid Build Coastguard Worker if key in context.parent: 129*635a8641SAndroid Build Coastguard Worker return context.parent[key] 130*635a8641SAndroid Build Coastguard Worker return missing 131*635a8641SAndroid Build Coastguard Worker 132*635a8641SAndroid Build Coastguard Worker 133*635a8641SAndroid Build Coastguard Workerclass Context(with_metaclass(ContextMeta)): 134*635a8641SAndroid Build Coastguard Worker """The template context holds the variables of a template. It stores the 135*635a8641SAndroid Build Coastguard Worker values passed to the template and also the names the template exports. 136*635a8641SAndroid Build Coastguard Worker Creating instances is neither supported nor useful as it's created 137*635a8641SAndroid Build Coastguard Worker automatically at various stages of the template evaluation and should not 138*635a8641SAndroid Build Coastguard Worker be created by hand. 139*635a8641SAndroid Build Coastguard Worker 140*635a8641SAndroid Build Coastguard Worker The context is immutable. Modifications on :attr:`parent` **must not** 141*635a8641SAndroid Build Coastguard Worker happen and modifications on :attr:`vars` are allowed from generated 142*635a8641SAndroid Build Coastguard Worker template code only. Template filters and global functions marked as 143*635a8641SAndroid Build Coastguard Worker :func:`contextfunction`\\s get the active context passed as first argument 144*635a8641SAndroid Build Coastguard Worker and are allowed to access the context read-only. 145*635a8641SAndroid Build Coastguard Worker 146*635a8641SAndroid Build Coastguard Worker The template context supports read only dict operations (`get`, 147*635a8641SAndroid Build Coastguard Worker `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`, 148*635a8641SAndroid Build Coastguard Worker `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve` 149*635a8641SAndroid Build Coastguard Worker method that doesn't fail with a `KeyError` but returns an 150*635a8641SAndroid Build Coastguard Worker :class:`Undefined` object for missing variables. 151*635a8641SAndroid Build Coastguard Worker """ 152*635a8641SAndroid Build Coastguard Worker # XXX: we want to eventually make this be a deprecation warning and 153*635a8641SAndroid Build Coastguard Worker # remove it. 154*635a8641SAndroid Build Coastguard Worker _legacy_resolve_mode = False 155*635a8641SAndroid Build Coastguard Worker _fast_resolve_mode = False 156*635a8641SAndroid Build Coastguard Worker 157*635a8641SAndroid Build Coastguard Worker def __init__(self, environment, parent, name, blocks): 158*635a8641SAndroid Build Coastguard Worker self.parent = parent 159*635a8641SAndroid Build Coastguard Worker self.vars = {} 160*635a8641SAndroid Build Coastguard Worker self.environment = environment 161*635a8641SAndroid Build Coastguard Worker self.eval_ctx = EvalContext(self.environment, name) 162*635a8641SAndroid Build Coastguard Worker self.exported_vars = set() 163*635a8641SAndroid Build Coastguard Worker self.name = name 164*635a8641SAndroid Build Coastguard Worker 165*635a8641SAndroid Build Coastguard Worker # create the initial mapping of blocks. Whenever template inheritance 166*635a8641SAndroid Build Coastguard Worker # takes place the runtime will update this mapping with the new blocks 167*635a8641SAndroid Build Coastguard Worker # from the template. 168*635a8641SAndroid Build Coastguard Worker self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) 169*635a8641SAndroid Build Coastguard Worker 170*635a8641SAndroid Build Coastguard Worker # In case we detect the fast resolve mode we can set up an alias 171*635a8641SAndroid Build Coastguard Worker # here that bypasses the legacy code logic. 172*635a8641SAndroid Build Coastguard Worker if self._fast_resolve_mode: 173*635a8641SAndroid Build Coastguard Worker self.resolve_or_missing = MethodType(resolve_or_missing, self) 174*635a8641SAndroid Build Coastguard Worker 175*635a8641SAndroid Build Coastguard Worker def super(self, name, current): 176*635a8641SAndroid Build Coastguard Worker """Render a parent block.""" 177*635a8641SAndroid Build Coastguard Worker try: 178*635a8641SAndroid Build Coastguard Worker blocks = self.blocks[name] 179*635a8641SAndroid Build Coastguard Worker index = blocks.index(current) + 1 180*635a8641SAndroid Build Coastguard Worker blocks[index] 181*635a8641SAndroid Build Coastguard Worker except LookupError: 182*635a8641SAndroid Build Coastguard Worker return self.environment.undefined('there is no parent block ' 183*635a8641SAndroid Build Coastguard Worker 'called %r.' % name, 184*635a8641SAndroid Build Coastguard Worker name='super') 185*635a8641SAndroid Build Coastguard Worker return BlockReference(name, self, blocks, index) 186*635a8641SAndroid Build Coastguard Worker 187*635a8641SAndroid Build Coastguard Worker def get(self, key, default=None): 188*635a8641SAndroid Build Coastguard Worker """Returns an item from the template context, if it doesn't exist 189*635a8641SAndroid Build Coastguard Worker `default` is returned. 190*635a8641SAndroid Build Coastguard Worker """ 191*635a8641SAndroid Build Coastguard Worker try: 192*635a8641SAndroid Build Coastguard Worker return self[key] 193*635a8641SAndroid Build Coastguard Worker except KeyError: 194*635a8641SAndroid Build Coastguard Worker return default 195*635a8641SAndroid Build Coastguard Worker 196*635a8641SAndroid Build Coastguard Worker def resolve(self, key): 197*635a8641SAndroid Build Coastguard Worker """Looks up a variable like `__getitem__` or `get` but returns an 198*635a8641SAndroid Build Coastguard Worker :class:`Undefined` object with the name of the name looked up. 199*635a8641SAndroid Build Coastguard Worker """ 200*635a8641SAndroid Build Coastguard Worker if self._legacy_resolve_mode: 201*635a8641SAndroid Build Coastguard Worker rv = resolve_or_missing(self, key) 202*635a8641SAndroid Build Coastguard Worker else: 203*635a8641SAndroid Build Coastguard Worker rv = self.resolve_or_missing(key) 204*635a8641SAndroid Build Coastguard Worker if rv is missing: 205*635a8641SAndroid Build Coastguard Worker return self.environment.undefined(name=key) 206*635a8641SAndroid Build Coastguard Worker return rv 207*635a8641SAndroid Build Coastguard Worker 208*635a8641SAndroid Build Coastguard Worker def resolve_or_missing(self, key): 209*635a8641SAndroid Build Coastguard Worker """Resolves a variable like :meth:`resolve` but returns the 210*635a8641SAndroid Build Coastguard Worker special `missing` value if it cannot be found. 211*635a8641SAndroid Build Coastguard Worker """ 212*635a8641SAndroid Build Coastguard Worker if self._legacy_resolve_mode: 213*635a8641SAndroid Build Coastguard Worker rv = self.resolve(key) 214*635a8641SAndroid Build Coastguard Worker if isinstance(rv, Undefined): 215*635a8641SAndroid Build Coastguard Worker rv = missing 216*635a8641SAndroid Build Coastguard Worker return rv 217*635a8641SAndroid Build Coastguard Worker return resolve_or_missing(self, key) 218*635a8641SAndroid Build Coastguard Worker 219*635a8641SAndroid Build Coastguard Worker def get_exported(self): 220*635a8641SAndroid Build Coastguard Worker """Get a new dict with the exported variables.""" 221*635a8641SAndroid Build Coastguard Worker return dict((k, self.vars[k]) for k in self.exported_vars) 222*635a8641SAndroid Build Coastguard Worker 223*635a8641SAndroid Build Coastguard Worker def get_all(self): 224*635a8641SAndroid Build Coastguard Worker """Return the complete context as dict including the exported 225*635a8641SAndroid Build Coastguard Worker variables. For optimizations reasons this might not return an 226*635a8641SAndroid Build Coastguard Worker actual copy so be careful with using it. 227*635a8641SAndroid Build Coastguard Worker """ 228*635a8641SAndroid Build Coastguard Worker if not self.vars: 229*635a8641SAndroid Build Coastguard Worker return self.parent 230*635a8641SAndroid Build Coastguard Worker if not self.parent: 231*635a8641SAndroid Build Coastguard Worker return self.vars 232*635a8641SAndroid Build Coastguard Worker return dict(self.parent, **self.vars) 233*635a8641SAndroid Build Coastguard Worker 234*635a8641SAndroid Build Coastguard Worker @internalcode 235*635a8641SAndroid Build Coastguard Worker def call(__self, __obj, *args, **kwargs): 236*635a8641SAndroid Build Coastguard Worker """Call the callable with the arguments and keyword arguments 237*635a8641SAndroid Build Coastguard Worker provided but inject the active context or environment as first 238*635a8641SAndroid Build Coastguard Worker argument if the callable is a :func:`contextfunction` or 239*635a8641SAndroid Build Coastguard Worker :func:`environmentfunction`. 240*635a8641SAndroid Build Coastguard Worker """ 241*635a8641SAndroid Build Coastguard Worker if __debug__: 242*635a8641SAndroid Build Coastguard Worker __traceback_hide__ = True # noqa 243*635a8641SAndroid Build Coastguard Worker 244*635a8641SAndroid Build Coastguard Worker # Allow callable classes to take a context 245*635a8641SAndroid Build Coastguard Worker if hasattr(__obj, '__call__'): 246*635a8641SAndroid Build Coastguard Worker fn = __obj.__call__ 247*635a8641SAndroid Build Coastguard Worker for fn_type in ('contextfunction', 248*635a8641SAndroid Build Coastguard Worker 'evalcontextfunction', 249*635a8641SAndroid Build Coastguard Worker 'environmentfunction'): 250*635a8641SAndroid Build Coastguard Worker if hasattr(fn, fn_type): 251*635a8641SAndroid Build Coastguard Worker __obj = fn 252*635a8641SAndroid Build Coastguard Worker break 253*635a8641SAndroid Build Coastguard Worker 254*635a8641SAndroid Build Coastguard Worker if isinstance(__obj, _context_function_types): 255*635a8641SAndroid Build Coastguard Worker if getattr(__obj, 'contextfunction', 0): 256*635a8641SAndroid Build Coastguard Worker args = (__self,) + args 257*635a8641SAndroid Build Coastguard Worker elif getattr(__obj, 'evalcontextfunction', 0): 258*635a8641SAndroid Build Coastguard Worker args = (__self.eval_ctx,) + args 259*635a8641SAndroid Build Coastguard Worker elif getattr(__obj, 'environmentfunction', 0): 260*635a8641SAndroid Build Coastguard Worker args = (__self.environment,) + args 261*635a8641SAndroid Build Coastguard Worker try: 262*635a8641SAndroid Build Coastguard Worker return __obj(*args, **kwargs) 263*635a8641SAndroid Build Coastguard Worker except StopIteration: 264*635a8641SAndroid Build Coastguard Worker return __self.environment.undefined('value was undefined because ' 265*635a8641SAndroid Build Coastguard Worker 'a callable raised a ' 266*635a8641SAndroid Build Coastguard Worker 'StopIteration exception') 267*635a8641SAndroid Build Coastguard Worker 268*635a8641SAndroid Build Coastguard Worker def derived(self, locals=None): 269*635a8641SAndroid Build Coastguard Worker """Internal helper function to create a derived context. This is 270*635a8641SAndroid Build Coastguard Worker used in situations where the system needs a new context in the same 271*635a8641SAndroid Build Coastguard Worker template that is independent. 272*635a8641SAndroid Build Coastguard Worker """ 273*635a8641SAndroid Build Coastguard Worker context = new_context(self.environment, self.name, {}, 274*635a8641SAndroid Build Coastguard Worker self.get_all(), True, None, locals) 275*635a8641SAndroid Build Coastguard Worker context.eval_ctx = self.eval_ctx 276*635a8641SAndroid Build Coastguard Worker context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) 277*635a8641SAndroid Build Coastguard Worker return context 278*635a8641SAndroid Build Coastguard Worker 279*635a8641SAndroid Build Coastguard Worker def _all(meth): 280*635a8641SAndroid Build Coastguard Worker proxy = lambda self: getattr(self.get_all(), meth)() 281*635a8641SAndroid Build Coastguard Worker proxy.__doc__ = getattr(dict, meth).__doc__ 282*635a8641SAndroid Build Coastguard Worker proxy.__name__ = meth 283*635a8641SAndroid Build Coastguard Worker return proxy 284*635a8641SAndroid Build Coastguard Worker 285*635a8641SAndroid Build Coastguard Worker keys = _all('keys') 286*635a8641SAndroid Build Coastguard Worker values = _all('values') 287*635a8641SAndroid Build Coastguard Worker items = _all('items') 288*635a8641SAndroid Build Coastguard Worker 289*635a8641SAndroid Build Coastguard Worker # not available on python 3 290*635a8641SAndroid Build Coastguard Worker if PY2: 291*635a8641SAndroid Build Coastguard Worker iterkeys = _all('iterkeys') 292*635a8641SAndroid Build Coastguard Worker itervalues = _all('itervalues') 293*635a8641SAndroid Build Coastguard Worker iteritems = _all('iteritems') 294*635a8641SAndroid Build Coastguard Worker del _all 295*635a8641SAndroid Build Coastguard Worker 296*635a8641SAndroid Build Coastguard Worker def __contains__(self, name): 297*635a8641SAndroid Build Coastguard Worker return name in self.vars or name in self.parent 298*635a8641SAndroid Build Coastguard Worker 299*635a8641SAndroid Build Coastguard Worker def __getitem__(self, key): 300*635a8641SAndroid Build Coastguard Worker """Lookup a variable or raise `KeyError` if the variable is 301*635a8641SAndroid Build Coastguard Worker undefined. 302*635a8641SAndroid Build Coastguard Worker """ 303*635a8641SAndroid Build Coastguard Worker item = self.resolve_or_missing(key) 304*635a8641SAndroid Build Coastguard Worker if item is missing: 305*635a8641SAndroid Build Coastguard Worker raise KeyError(key) 306*635a8641SAndroid Build Coastguard Worker return item 307*635a8641SAndroid Build Coastguard Worker 308*635a8641SAndroid Build Coastguard Worker def __repr__(self): 309*635a8641SAndroid Build Coastguard Worker return '<%s %s of %r>' % ( 310*635a8641SAndroid Build Coastguard Worker self.__class__.__name__, 311*635a8641SAndroid Build Coastguard Worker repr(self.get_all()), 312*635a8641SAndroid Build Coastguard Worker self.name 313*635a8641SAndroid Build Coastguard Worker ) 314*635a8641SAndroid Build Coastguard Worker 315*635a8641SAndroid Build Coastguard Worker 316*635a8641SAndroid Build Coastguard Worker# register the context as mapping if possible 317*635a8641SAndroid Build Coastguard Workertry: 318*635a8641SAndroid Build Coastguard Worker from collections import Mapping 319*635a8641SAndroid Build Coastguard Worker Mapping.register(Context) 320*635a8641SAndroid Build Coastguard Workerexcept ImportError: 321*635a8641SAndroid Build Coastguard Worker pass 322*635a8641SAndroid Build Coastguard Worker 323*635a8641SAndroid Build Coastguard Worker 324*635a8641SAndroid Build Coastguard Workerclass BlockReference(object): 325*635a8641SAndroid Build Coastguard Worker """One block on a template reference.""" 326*635a8641SAndroid Build Coastguard Worker 327*635a8641SAndroid Build Coastguard Worker def __init__(self, name, context, stack, depth): 328*635a8641SAndroid Build Coastguard Worker self.name = name 329*635a8641SAndroid Build Coastguard Worker self._context = context 330*635a8641SAndroid Build Coastguard Worker self._stack = stack 331*635a8641SAndroid Build Coastguard Worker self._depth = depth 332*635a8641SAndroid Build Coastguard Worker 333*635a8641SAndroid Build Coastguard Worker @property 334*635a8641SAndroid Build Coastguard Worker def super(self): 335*635a8641SAndroid Build Coastguard Worker """Super the block.""" 336*635a8641SAndroid Build Coastguard Worker if self._depth + 1 >= len(self._stack): 337*635a8641SAndroid Build Coastguard Worker return self._context.environment. \ 338*635a8641SAndroid Build Coastguard Worker undefined('there is no parent block called %r.' % 339*635a8641SAndroid Build Coastguard Worker self.name, name='super') 340*635a8641SAndroid Build Coastguard Worker return BlockReference(self.name, self._context, self._stack, 341*635a8641SAndroid Build Coastguard Worker self._depth + 1) 342*635a8641SAndroid Build Coastguard Worker 343*635a8641SAndroid Build Coastguard Worker @internalcode 344*635a8641SAndroid Build Coastguard Worker def __call__(self): 345*635a8641SAndroid Build Coastguard Worker rv = concat(self._stack[self._depth](self._context)) 346*635a8641SAndroid Build Coastguard Worker if self._context.eval_ctx.autoescape: 347*635a8641SAndroid Build Coastguard Worker rv = Markup(rv) 348*635a8641SAndroid Build Coastguard Worker return rv 349*635a8641SAndroid Build Coastguard Worker 350*635a8641SAndroid Build Coastguard Worker 351*635a8641SAndroid Build Coastguard Workerclass LoopContextBase(object): 352*635a8641SAndroid Build Coastguard Worker """A loop context for dynamic iteration.""" 353*635a8641SAndroid Build Coastguard Worker 354*635a8641SAndroid Build Coastguard Worker _before = _first_iteration 355*635a8641SAndroid Build Coastguard Worker _current = _first_iteration 356*635a8641SAndroid Build Coastguard Worker _after = _last_iteration 357*635a8641SAndroid Build Coastguard Worker _length = None 358*635a8641SAndroid Build Coastguard Worker 359*635a8641SAndroid Build Coastguard Worker def __init__(self, undefined, recurse=None, depth0=0): 360*635a8641SAndroid Build Coastguard Worker self._undefined = undefined 361*635a8641SAndroid Build Coastguard Worker self._recurse = recurse 362*635a8641SAndroid Build Coastguard Worker self.index0 = -1 363*635a8641SAndroid Build Coastguard Worker self.depth0 = depth0 364*635a8641SAndroid Build Coastguard Worker self._last_checked_value = missing 365*635a8641SAndroid Build Coastguard Worker 366*635a8641SAndroid Build Coastguard Worker def cycle(self, *args): 367*635a8641SAndroid Build Coastguard Worker """Cycles among the arguments with the current loop index.""" 368*635a8641SAndroid Build Coastguard Worker if not args: 369*635a8641SAndroid Build Coastguard Worker raise TypeError('no items for cycling given') 370*635a8641SAndroid Build Coastguard Worker return args[self.index0 % len(args)] 371*635a8641SAndroid Build Coastguard Worker 372*635a8641SAndroid Build Coastguard Worker def changed(self, *value): 373*635a8641SAndroid Build Coastguard Worker """Checks whether the value has changed since the last call.""" 374*635a8641SAndroid Build Coastguard Worker if self._last_checked_value != value: 375*635a8641SAndroid Build Coastguard Worker self._last_checked_value = value 376*635a8641SAndroid Build Coastguard Worker return True 377*635a8641SAndroid Build Coastguard Worker return False 378*635a8641SAndroid Build Coastguard Worker 379*635a8641SAndroid Build Coastguard Worker first = property(lambda x: x.index0 == 0) 380*635a8641SAndroid Build Coastguard Worker last = property(lambda x: x._after is _last_iteration) 381*635a8641SAndroid Build Coastguard Worker index = property(lambda x: x.index0 + 1) 382*635a8641SAndroid Build Coastguard Worker revindex = property(lambda x: x.length - x.index0) 383*635a8641SAndroid Build Coastguard Worker revindex0 = property(lambda x: x.length - x.index) 384*635a8641SAndroid Build Coastguard Worker depth = property(lambda x: x.depth0 + 1) 385*635a8641SAndroid Build Coastguard Worker 386*635a8641SAndroid Build Coastguard Worker @property 387*635a8641SAndroid Build Coastguard Worker def previtem(self): 388*635a8641SAndroid Build Coastguard Worker if self._before is _first_iteration: 389*635a8641SAndroid Build Coastguard Worker return self._undefined('there is no previous item') 390*635a8641SAndroid Build Coastguard Worker return self._before 391*635a8641SAndroid Build Coastguard Worker 392*635a8641SAndroid Build Coastguard Worker @property 393*635a8641SAndroid Build Coastguard Worker def nextitem(self): 394*635a8641SAndroid Build Coastguard Worker if self._after is _last_iteration: 395*635a8641SAndroid Build Coastguard Worker return self._undefined('there is no next item') 396*635a8641SAndroid Build Coastguard Worker return self._after 397*635a8641SAndroid Build Coastguard Worker 398*635a8641SAndroid Build Coastguard Worker def __len__(self): 399*635a8641SAndroid Build Coastguard Worker return self.length 400*635a8641SAndroid Build Coastguard Worker 401*635a8641SAndroid Build Coastguard Worker @internalcode 402*635a8641SAndroid Build Coastguard Worker def loop(self, iterable): 403*635a8641SAndroid Build Coastguard Worker if self._recurse is None: 404*635a8641SAndroid Build Coastguard Worker raise TypeError('Tried to call non recursive loop. Maybe you ' 405*635a8641SAndroid Build Coastguard Worker "forgot the 'recursive' modifier.") 406*635a8641SAndroid Build Coastguard Worker return self._recurse(iterable, self._recurse, self.depth0 + 1) 407*635a8641SAndroid Build Coastguard Worker 408*635a8641SAndroid Build Coastguard Worker # a nifty trick to enhance the error message if someone tried to call 409*635a8641SAndroid Build Coastguard Worker # the the loop without or with too many arguments. 410*635a8641SAndroid Build Coastguard Worker __call__ = loop 411*635a8641SAndroid Build Coastguard Worker del loop 412*635a8641SAndroid Build Coastguard Worker 413*635a8641SAndroid Build Coastguard Worker def __repr__(self): 414*635a8641SAndroid Build Coastguard Worker return '<%s %r/%r>' % ( 415*635a8641SAndroid Build Coastguard Worker self.__class__.__name__, 416*635a8641SAndroid Build Coastguard Worker self.index, 417*635a8641SAndroid Build Coastguard Worker self.length 418*635a8641SAndroid Build Coastguard Worker ) 419*635a8641SAndroid Build Coastguard Worker 420*635a8641SAndroid Build Coastguard Worker 421*635a8641SAndroid Build Coastguard Workerclass LoopContext(LoopContextBase): 422*635a8641SAndroid Build Coastguard Worker 423*635a8641SAndroid Build Coastguard Worker def __init__(self, iterable, undefined, recurse=None, depth0=0): 424*635a8641SAndroid Build Coastguard Worker LoopContextBase.__init__(self, undefined, recurse, depth0) 425*635a8641SAndroid Build Coastguard Worker self._iterator = iter(iterable) 426*635a8641SAndroid Build Coastguard Worker 427*635a8641SAndroid Build Coastguard Worker # try to get the length of the iterable early. This must be done 428*635a8641SAndroid Build Coastguard Worker # here because there are some broken iterators around where there 429*635a8641SAndroid Build Coastguard Worker # __len__ is the number of iterations left (i'm looking at your 430*635a8641SAndroid Build Coastguard Worker # listreverseiterator!). 431*635a8641SAndroid Build Coastguard Worker try: 432*635a8641SAndroid Build Coastguard Worker self._length = len(iterable) 433*635a8641SAndroid Build Coastguard Worker except (TypeError, AttributeError): 434*635a8641SAndroid Build Coastguard Worker self._length = None 435*635a8641SAndroid Build Coastguard Worker self._after = self._safe_next() 436*635a8641SAndroid Build Coastguard Worker 437*635a8641SAndroid Build Coastguard Worker @property 438*635a8641SAndroid Build Coastguard Worker def length(self): 439*635a8641SAndroid Build Coastguard Worker if self._length is None: 440*635a8641SAndroid Build Coastguard Worker # if was not possible to get the length of the iterator when 441*635a8641SAndroid Build Coastguard Worker # the loop context was created (ie: iterating over a generator) 442*635a8641SAndroid Build Coastguard Worker # we have to convert the iterable into a sequence and use the 443*635a8641SAndroid Build Coastguard Worker # length of that + the number of iterations so far. 444*635a8641SAndroid Build Coastguard Worker iterable = tuple(self._iterator) 445*635a8641SAndroid Build Coastguard Worker self._iterator = iter(iterable) 446*635a8641SAndroid Build Coastguard Worker iterations_done = self.index0 + 2 447*635a8641SAndroid Build Coastguard Worker self._length = len(iterable) + iterations_done 448*635a8641SAndroid Build Coastguard Worker return self._length 449*635a8641SAndroid Build Coastguard Worker 450*635a8641SAndroid Build Coastguard Worker def __iter__(self): 451*635a8641SAndroid Build Coastguard Worker return LoopContextIterator(self) 452*635a8641SAndroid Build Coastguard Worker 453*635a8641SAndroid Build Coastguard Worker def _safe_next(self): 454*635a8641SAndroid Build Coastguard Worker try: 455*635a8641SAndroid Build Coastguard Worker return next(self._iterator) 456*635a8641SAndroid Build Coastguard Worker except StopIteration: 457*635a8641SAndroid Build Coastguard Worker return _last_iteration 458*635a8641SAndroid Build Coastguard Worker 459*635a8641SAndroid Build Coastguard Worker 460*635a8641SAndroid Build Coastguard Worker@implements_iterator 461*635a8641SAndroid Build Coastguard Workerclass LoopContextIterator(object): 462*635a8641SAndroid Build Coastguard Worker """The iterator for a loop context.""" 463*635a8641SAndroid Build Coastguard Worker __slots__ = ('context',) 464*635a8641SAndroid Build Coastguard Worker 465*635a8641SAndroid Build Coastguard Worker def __init__(self, context): 466*635a8641SAndroid Build Coastguard Worker self.context = context 467*635a8641SAndroid Build Coastguard Worker 468*635a8641SAndroid Build Coastguard Worker def __iter__(self): 469*635a8641SAndroid Build Coastguard Worker return self 470*635a8641SAndroid Build Coastguard Worker 471*635a8641SAndroid Build Coastguard Worker def __next__(self): 472*635a8641SAndroid Build Coastguard Worker ctx = self.context 473*635a8641SAndroid Build Coastguard Worker ctx.index0 += 1 474*635a8641SAndroid Build Coastguard Worker if ctx._after is _last_iteration: 475*635a8641SAndroid Build Coastguard Worker raise StopIteration() 476*635a8641SAndroid Build Coastguard Worker ctx._before = ctx._current 477*635a8641SAndroid Build Coastguard Worker ctx._current = ctx._after 478*635a8641SAndroid Build Coastguard Worker ctx._after = ctx._safe_next() 479*635a8641SAndroid Build Coastguard Worker return ctx._current, ctx 480*635a8641SAndroid Build Coastguard Worker 481*635a8641SAndroid Build Coastguard Worker 482*635a8641SAndroid Build Coastguard Workerclass Macro(object): 483*635a8641SAndroid Build Coastguard Worker """Wraps a macro function.""" 484*635a8641SAndroid Build Coastguard Worker 485*635a8641SAndroid Build Coastguard Worker def __init__(self, environment, func, name, arguments, 486*635a8641SAndroid Build Coastguard Worker catch_kwargs, catch_varargs, caller, 487*635a8641SAndroid Build Coastguard Worker default_autoescape=None): 488*635a8641SAndroid Build Coastguard Worker self._environment = environment 489*635a8641SAndroid Build Coastguard Worker self._func = func 490*635a8641SAndroid Build Coastguard Worker self._argument_count = len(arguments) 491*635a8641SAndroid Build Coastguard Worker self.name = name 492*635a8641SAndroid Build Coastguard Worker self.arguments = arguments 493*635a8641SAndroid Build Coastguard Worker self.catch_kwargs = catch_kwargs 494*635a8641SAndroid Build Coastguard Worker self.catch_varargs = catch_varargs 495*635a8641SAndroid Build Coastguard Worker self.caller = caller 496*635a8641SAndroid Build Coastguard Worker self.explicit_caller = 'caller' in arguments 497*635a8641SAndroid Build Coastguard Worker if default_autoescape is None: 498*635a8641SAndroid Build Coastguard Worker default_autoescape = environment.autoescape 499*635a8641SAndroid Build Coastguard Worker self._default_autoescape = default_autoescape 500*635a8641SAndroid Build Coastguard Worker 501*635a8641SAndroid Build Coastguard Worker @internalcode 502*635a8641SAndroid Build Coastguard Worker @evalcontextfunction 503*635a8641SAndroid Build Coastguard Worker def __call__(self, *args, **kwargs): 504*635a8641SAndroid Build Coastguard Worker # This requires a bit of explanation, In the past we used to 505*635a8641SAndroid Build Coastguard Worker # decide largely based on compile-time information if a macro is 506*635a8641SAndroid Build Coastguard Worker # safe or unsafe. While there was a volatile mode it was largely 507*635a8641SAndroid Build Coastguard Worker # unused for deciding on escaping. This turns out to be 508*635a8641SAndroid Build Coastguard Worker # problemtic for macros because if a macro is safe or not not so 509*635a8641SAndroid Build Coastguard Worker # much depends on the escape mode when it was defined but when it 510*635a8641SAndroid Build Coastguard Worker # was used. 511*635a8641SAndroid Build Coastguard Worker # 512*635a8641SAndroid Build Coastguard Worker # Because however we export macros from the module system and 513*635a8641SAndroid Build Coastguard Worker # there are historic callers that do not pass an eval context (and 514*635a8641SAndroid Build Coastguard Worker # will continue to not pass one), we need to perform an instance 515*635a8641SAndroid Build Coastguard Worker # check here. 516*635a8641SAndroid Build Coastguard Worker # 517*635a8641SAndroid Build Coastguard Worker # This is considered safe because an eval context is not a valid 518*635a8641SAndroid Build Coastguard Worker # argument to callables otherwise anwyays. Worst case here is 519*635a8641SAndroid Build Coastguard Worker # that if no eval context is passed we fall back to the compile 520*635a8641SAndroid Build Coastguard Worker # time autoescape flag. 521*635a8641SAndroid Build Coastguard Worker if args and isinstance(args[0], EvalContext): 522*635a8641SAndroid Build Coastguard Worker autoescape = args[0].autoescape 523*635a8641SAndroid Build Coastguard Worker args = args[1:] 524*635a8641SAndroid Build Coastguard Worker else: 525*635a8641SAndroid Build Coastguard Worker autoescape = self._default_autoescape 526*635a8641SAndroid Build Coastguard Worker 527*635a8641SAndroid Build Coastguard Worker # try to consume the positional arguments 528*635a8641SAndroid Build Coastguard Worker arguments = list(args[:self._argument_count]) 529*635a8641SAndroid Build Coastguard Worker off = len(arguments) 530*635a8641SAndroid Build Coastguard Worker 531*635a8641SAndroid Build Coastguard Worker # For information why this is necessary refer to the handling 532*635a8641SAndroid Build Coastguard Worker # of caller in the `macro_body` handler in the compiler. 533*635a8641SAndroid Build Coastguard Worker found_caller = False 534*635a8641SAndroid Build Coastguard Worker 535*635a8641SAndroid Build Coastguard Worker # if the number of arguments consumed is not the number of 536*635a8641SAndroid Build Coastguard Worker # arguments expected we start filling in keyword arguments 537*635a8641SAndroid Build Coastguard Worker # and defaults. 538*635a8641SAndroid Build Coastguard Worker if off != self._argument_count: 539*635a8641SAndroid Build Coastguard Worker for idx, name in enumerate(self.arguments[len(arguments):]): 540*635a8641SAndroid Build Coastguard Worker try: 541*635a8641SAndroid Build Coastguard Worker value = kwargs.pop(name) 542*635a8641SAndroid Build Coastguard Worker except KeyError: 543*635a8641SAndroid Build Coastguard Worker value = missing 544*635a8641SAndroid Build Coastguard Worker if name == 'caller': 545*635a8641SAndroid Build Coastguard Worker found_caller = True 546*635a8641SAndroid Build Coastguard Worker arguments.append(value) 547*635a8641SAndroid Build Coastguard Worker else: 548*635a8641SAndroid Build Coastguard Worker found_caller = self.explicit_caller 549*635a8641SAndroid Build Coastguard Worker 550*635a8641SAndroid Build Coastguard Worker # it's important that the order of these arguments does not change 551*635a8641SAndroid Build Coastguard Worker # if not also changed in the compiler's `function_scoping` method. 552*635a8641SAndroid Build Coastguard Worker # the order is caller, keyword arguments, positional arguments! 553*635a8641SAndroid Build Coastguard Worker if self.caller and not found_caller: 554*635a8641SAndroid Build Coastguard Worker caller = kwargs.pop('caller', None) 555*635a8641SAndroid Build Coastguard Worker if caller is None: 556*635a8641SAndroid Build Coastguard Worker caller = self._environment.undefined('No caller defined', 557*635a8641SAndroid Build Coastguard Worker name='caller') 558*635a8641SAndroid Build Coastguard Worker arguments.append(caller) 559*635a8641SAndroid Build Coastguard Worker 560*635a8641SAndroid Build Coastguard Worker if self.catch_kwargs: 561*635a8641SAndroid Build Coastguard Worker arguments.append(kwargs) 562*635a8641SAndroid Build Coastguard Worker elif kwargs: 563*635a8641SAndroid Build Coastguard Worker if 'caller' in kwargs: 564*635a8641SAndroid Build Coastguard Worker raise TypeError('macro %r was invoked with two values for ' 565*635a8641SAndroid Build Coastguard Worker 'the special caller argument. This is ' 566*635a8641SAndroid Build Coastguard Worker 'most likely a bug.' % self.name) 567*635a8641SAndroid Build Coastguard Worker raise TypeError('macro %r takes no keyword argument %r' % 568*635a8641SAndroid Build Coastguard Worker (self.name, next(iter(kwargs)))) 569*635a8641SAndroid Build Coastguard Worker if self.catch_varargs: 570*635a8641SAndroid Build Coastguard Worker arguments.append(args[self._argument_count:]) 571*635a8641SAndroid Build Coastguard Worker elif len(args) > self._argument_count: 572*635a8641SAndroid Build Coastguard Worker raise TypeError('macro %r takes not more than %d argument(s)' % 573*635a8641SAndroid Build Coastguard Worker (self.name, len(self.arguments))) 574*635a8641SAndroid Build Coastguard Worker 575*635a8641SAndroid Build Coastguard Worker return self._invoke(arguments, autoescape) 576*635a8641SAndroid Build Coastguard Worker 577*635a8641SAndroid Build Coastguard Worker def _invoke(self, arguments, autoescape): 578*635a8641SAndroid Build Coastguard Worker """This method is being swapped out by the async implementation.""" 579*635a8641SAndroid Build Coastguard Worker rv = self._func(*arguments) 580*635a8641SAndroid Build Coastguard Worker if autoescape: 581*635a8641SAndroid Build Coastguard Worker rv = Markup(rv) 582*635a8641SAndroid Build Coastguard Worker return rv 583*635a8641SAndroid Build Coastguard Worker 584*635a8641SAndroid Build Coastguard Worker def __repr__(self): 585*635a8641SAndroid Build Coastguard Worker return '<%s %s>' % ( 586*635a8641SAndroid Build Coastguard Worker self.__class__.__name__, 587*635a8641SAndroid Build Coastguard Worker self.name is None and 'anonymous' or repr(self.name) 588*635a8641SAndroid Build Coastguard Worker ) 589*635a8641SAndroid Build Coastguard Worker 590*635a8641SAndroid Build Coastguard Worker 591*635a8641SAndroid Build Coastguard Worker@implements_to_string 592*635a8641SAndroid Build Coastguard Workerclass Undefined(object): 593*635a8641SAndroid Build Coastguard Worker """The default undefined type. This undefined type can be printed and 594*635a8641SAndroid Build Coastguard Worker iterated over, but every other access will raise an :exc:`jinja2.exceptions.UndefinedError`: 595*635a8641SAndroid Build Coastguard Worker 596*635a8641SAndroid Build Coastguard Worker >>> foo = Undefined(name='foo') 597*635a8641SAndroid Build Coastguard Worker >>> str(foo) 598*635a8641SAndroid Build Coastguard Worker '' 599*635a8641SAndroid Build Coastguard Worker >>> not foo 600*635a8641SAndroid Build Coastguard Worker True 601*635a8641SAndroid Build Coastguard Worker >>> foo + 42 602*635a8641SAndroid Build Coastguard Worker Traceback (most recent call last): 603*635a8641SAndroid Build Coastguard Worker ... 604*635a8641SAndroid Build Coastguard Worker jinja2.exceptions.UndefinedError: 'foo' is undefined 605*635a8641SAndroid Build Coastguard Worker """ 606*635a8641SAndroid Build Coastguard Worker __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name', 607*635a8641SAndroid Build Coastguard Worker '_undefined_exception') 608*635a8641SAndroid Build Coastguard Worker 609*635a8641SAndroid Build Coastguard Worker def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): 610*635a8641SAndroid Build Coastguard Worker self._undefined_hint = hint 611*635a8641SAndroid Build Coastguard Worker self._undefined_obj = obj 612*635a8641SAndroid Build Coastguard Worker self._undefined_name = name 613*635a8641SAndroid Build Coastguard Worker self._undefined_exception = exc 614*635a8641SAndroid Build Coastguard Worker 615*635a8641SAndroid Build Coastguard Worker @internalcode 616*635a8641SAndroid Build Coastguard Worker def _fail_with_undefined_error(self, *args, **kwargs): 617*635a8641SAndroid Build Coastguard Worker """Regular callback function for undefined objects that raises an 618*635a8641SAndroid Build Coastguard Worker `jinja2.exceptions.UndefinedError` on call. 619*635a8641SAndroid Build Coastguard Worker """ 620*635a8641SAndroid Build Coastguard Worker if self._undefined_hint is None: 621*635a8641SAndroid Build Coastguard Worker if self._undefined_obj is missing: 622*635a8641SAndroid Build Coastguard Worker hint = '%r is undefined' % self._undefined_name 623*635a8641SAndroid Build Coastguard Worker elif not isinstance(self._undefined_name, string_types): 624*635a8641SAndroid Build Coastguard Worker hint = '%s has no element %r' % ( 625*635a8641SAndroid Build Coastguard Worker object_type_repr(self._undefined_obj), 626*635a8641SAndroid Build Coastguard Worker self._undefined_name 627*635a8641SAndroid Build Coastguard Worker ) 628*635a8641SAndroid Build Coastguard Worker else: 629*635a8641SAndroid Build Coastguard Worker hint = '%r has no attribute %r' % ( 630*635a8641SAndroid Build Coastguard Worker object_type_repr(self._undefined_obj), 631*635a8641SAndroid Build Coastguard Worker self._undefined_name 632*635a8641SAndroid Build Coastguard Worker ) 633*635a8641SAndroid Build Coastguard Worker else: 634*635a8641SAndroid Build Coastguard Worker hint = self._undefined_hint 635*635a8641SAndroid Build Coastguard Worker raise self._undefined_exception(hint) 636*635a8641SAndroid Build Coastguard Worker 637*635a8641SAndroid Build Coastguard Worker @internalcode 638*635a8641SAndroid Build Coastguard Worker def __getattr__(self, name): 639*635a8641SAndroid Build Coastguard Worker if name[:2] == '__': 640*635a8641SAndroid Build Coastguard Worker raise AttributeError(name) 641*635a8641SAndroid Build Coastguard Worker return self._fail_with_undefined_error() 642*635a8641SAndroid Build Coastguard Worker 643*635a8641SAndroid Build Coastguard Worker __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \ 644*635a8641SAndroid Build Coastguard Worker __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \ 645*635a8641SAndroid Build Coastguard Worker __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \ 646*635a8641SAndroid Build Coastguard Worker __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \ 647*635a8641SAndroid Build Coastguard Worker __float__ = __complex__ = __pow__ = __rpow__ = __sub__ = \ 648*635a8641SAndroid Build Coastguard Worker __rsub__ = _fail_with_undefined_error 649*635a8641SAndroid Build Coastguard Worker 650*635a8641SAndroid Build Coastguard Worker def __eq__(self, other): 651*635a8641SAndroid Build Coastguard Worker return type(self) is type(other) 652*635a8641SAndroid Build Coastguard Worker 653*635a8641SAndroid Build Coastguard Worker def __ne__(self, other): 654*635a8641SAndroid Build Coastguard Worker return not self.__eq__(other) 655*635a8641SAndroid Build Coastguard Worker 656*635a8641SAndroid Build Coastguard Worker def __hash__(self): 657*635a8641SAndroid Build Coastguard Worker return id(type(self)) 658*635a8641SAndroid Build Coastguard Worker 659*635a8641SAndroid Build Coastguard Worker def __str__(self): 660*635a8641SAndroid Build Coastguard Worker return u'' 661*635a8641SAndroid Build Coastguard Worker 662*635a8641SAndroid Build Coastguard Worker def __len__(self): 663*635a8641SAndroid Build Coastguard Worker return 0 664*635a8641SAndroid Build Coastguard Worker 665*635a8641SAndroid Build Coastguard Worker def __iter__(self): 666*635a8641SAndroid Build Coastguard Worker if 0: 667*635a8641SAndroid Build Coastguard Worker yield None 668*635a8641SAndroid Build Coastguard Worker 669*635a8641SAndroid Build Coastguard Worker def __nonzero__(self): 670*635a8641SAndroid Build Coastguard Worker return False 671*635a8641SAndroid Build Coastguard Worker __bool__ = __nonzero__ 672*635a8641SAndroid Build Coastguard Worker 673*635a8641SAndroid Build Coastguard Worker def __repr__(self): 674*635a8641SAndroid Build Coastguard Worker return 'Undefined' 675*635a8641SAndroid Build Coastguard Worker 676*635a8641SAndroid Build Coastguard Worker 677*635a8641SAndroid Build Coastguard Workerdef make_logging_undefined(logger=None, base=None): 678*635a8641SAndroid Build Coastguard Worker """Given a logger object this returns a new undefined class that will 679*635a8641SAndroid Build Coastguard Worker log certain failures. It will log iterations and printing. If no 680*635a8641SAndroid Build Coastguard Worker logger is given a default logger is created. 681*635a8641SAndroid Build Coastguard Worker 682*635a8641SAndroid Build Coastguard Worker Example:: 683*635a8641SAndroid Build Coastguard Worker 684*635a8641SAndroid Build Coastguard Worker logger = logging.getLogger(__name__) 685*635a8641SAndroid Build Coastguard Worker LoggingUndefined = make_logging_undefined( 686*635a8641SAndroid Build Coastguard Worker logger=logger, 687*635a8641SAndroid Build Coastguard Worker base=Undefined 688*635a8641SAndroid Build Coastguard Worker ) 689*635a8641SAndroid Build Coastguard Worker 690*635a8641SAndroid Build Coastguard Worker .. versionadded:: 2.8 691*635a8641SAndroid Build Coastguard Worker 692*635a8641SAndroid Build Coastguard Worker :param logger: the logger to use. If not provided, a default logger 693*635a8641SAndroid Build Coastguard Worker is created. 694*635a8641SAndroid Build Coastguard Worker :param base: the base class to add logging functionality to. This 695*635a8641SAndroid Build Coastguard Worker defaults to :class:`Undefined`. 696*635a8641SAndroid Build Coastguard Worker """ 697*635a8641SAndroid Build Coastguard Worker if logger is None: 698*635a8641SAndroid Build Coastguard Worker import logging 699*635a8641SAndroid Build Coastguard Worker logger = logging.getLogger(__name__) 700*635a8641SAndroid Build Coastguard Worker logger.addHandler(logging.StreamHandler(sys.stderr)) 701*635a8641SAndroid Build Coastguard Worker if base is None: 702*635a8641SAndroid Build Coastguard Worker base = Undefined 703*635a8641SAndroid Build Coastguard Worker 704*635a8641SAndroid Build Coastguard Worker def _log_message(undef): 705*635a8641SAndroid Build Coastguard Worker if undef._undefined_hint is None: 706*635a8641SAndroid Build Coastguard Worker if undef._undefined_obj is missing: 707*635a8641SAndroid Build Coastguard Worker hint = '%s is undefined' % undef._undefined_name 708*635a8641SAndroid Build Coastguard Worker elif not isinstance(undef._undefined_name, string_types): 709*635a8641SAndroid Build Coastguard Worker hint = '%s has no element %s' % ( 710*635a8641SAndroid Build Coastguard Worker object_type_repr(undef._undefined_obj), 711*635a8641SAndroid Build Coastguard Worker undef._undefined_name) 712*635a8641SAndroid Build Coastguard Worker else: 713*635a8641SAndroid Build Coastguard Worker hint = '%s has no attribute %s' % ( 714*635a8641SAndroid Build Coastguard Worker object_type_repr(undef._undefined_obj), 715*635a8641SAndroid Build Coastguard Worker undef._undefined_name) 716*635a8641SAndroid Build Coastguard Worker else: 717*635a8641SAndroid Build Coastguard Worker hint = undef._undefined_hint 718*635a8641SAndroid Build Coastguard Worker logger.warning('Template variable warning: %s', hint) 719*635a8641SAndroid Build Coastguard Worker 720*635a8641SAndroid Build Coastguard Worker class LoggingUndefined(base): 721*635a8641SAndroid Build Coastguard Worker 722*635a8641SAndroid Build Coastguard Worker def _fail_with_undefined_error(self, *args, **kwargs): 723*635a8641SAndroid Build Coastguard Worker try: 724*635a8641SAndroid Build Coastguard Worker return base._fail_with_undefined_error(self, *args, **kwargs) 725*635a8641SAndroid Build Coastguard Worker except self._undefined_exception as e: 726*635a8641SAndroid Build Coastguard Worker logger.error('Template variable error: %s', str(e)) 727*635a8641SAndroid Build Coastguard Worker raise e 728*635a8641SAndroid Build Coastguard Worker 729*635a8641SAndroid Build Coastguard Worker def __str__(self): 730*635a8641SAndroid Build Coastguard Worker rv = base.__str__(self) 731*635a8641SAndroid Build Coastguard Worker _log_message(self) 732*635a8641SAndroid Build Coastguard Worker return rv 733*635a8641SAndroid Build Coastguard Worker 734*635a8641SAndroid Build Coastguard Worker def __iter__(self): 735*635a8641SAndroid Build Coastguard Worker rv = base.__iter__(self) 736*635a8641SAndroid Build Coastguard Worker _log_message(self) 737*635a8641SAndroid Build Coastguard Worker return rv 738*635a8641SAndroid Build Coastguard Worker 739*635a8641SAndroid Build Coastguard Worker if PY2: 740*635a8641SAndroid Build Coastguard Worker def __nonzero__(self): 741*635a8641SAndroid Build Coastguard Worker rv = base.__nonzero__(self) 742*635a8641SAndroid Build Coastguard Worker _log_message(self) 743*635a8641SAndroid Build Coastguard Worker return rv 744*635a8641SAndroid Build Coastguard Worker 745*635a8641SAndroid Build Coastguard Worker def __unicode__(self): 746*635a8641SAndroid Build Coastguard Worker rv = base.__unicode__(self) 747*635a8641SAndroid Build Coastguard Worker _log_message(self) 748*635a8641SAndroid Build Coastguard Worker return rv 749*635a8641SAndroid Build Coastguard Worker else: 750*635a8641SAndroid Build Coastguard Worker def __bool__(self): 751*635a8641SAndroid Build Coastguard Worker rv = base.__bool__(self) 752*635a8641SAndroid Build Coastguard Worker _log_message(self) 753*635a8641SAndroid Build Coastguard Worker return rv 754*635a8641SAndroid Build Coastguard Worker 755*635a8641SAndroid Build Coastguard Worker return LoggingUndefined 756*635a8641SAndroid Build Coastguard Worker 757*635a8641SAndroid Build Coastguard Worker 758*635a8641SAndroid Build Coastguard Worker@implements_to_string 759*635a8641SAndroid Build Coastguard Workerclass DebugUndefined(Undefined): 760*635a8641SAndroid Build Coastguard Worker """An undefined that returns the debug info when printed. 761*635a8641SAndroid Build Coastguard Worker 762*635a8641SAndroid Build Coastguard Worker >>> foo = DebugUndefined(name='foo') 763*635a8641SAndroid Build Coastguard Worker >>> str(foo) 764*635a8641SAndroid Build Coastguard Worker '{{ foo }}' 765*635a8641SAndroid Build Coastguard Worker >>> not foo 766*635a8641SAndroid Build Coastguard Worker True 767*635a8641SAndroid Build Coastguard Worker >>> foo + 42 768*635a8641SAndroid Build Coastguard Worker Traceback (most recent call last): 769*635a8641SAndroid Build Coastguard Worker ... 770*635a8641SAndroid Build Coastguard Worker jinja2.exceptions.UndefinedError: 'foo' is undefined 771*635a8641SAndroid Build Coastguard Worker """ 772*635a8641SAndroid Build Coastguard Worker __slots__ = () 773*635a8641SAndroid Build Coastguard Worker 774*635a8641SAndroid Build Coastguard Worker def __str__(self): 775*635a8641SAndroid Build Coastguard Worker if self._undefined_hint is None: 776*635a8641SAndroid Build Coastguard Worker if self._undefined_obj is missing: 777*635a8641SAndroid Build Coastguard Worker return u'{{ %s }}' % self._undefined_name 778*635a8641SAndroid Build Coastguard Worker return '{{ no such element: %s[%r] }}' % ( 779*635a8641SAndroid Build Coastguard Worker object_type_repr(self._undefined_obj), 780*635a8641SAndroid Build Coastguard Worker self._undefined_name 781*635a8641SAndroid Build Coastguard Worker ) 782*635a8641SAndroid Build Coastguard Worker return u'{{ undefined value printed: %s }}' % self._undefined_hint 783*635a8641SAndroid Build Coastguard Worker 784*635a8641SAndroid Build Coastguard Worker 785*635a8641SAndroid Build Coastguard Worker@implements_to_string 786*635a8641SAndroid Build Coastguard Workerclass StrictUndefined(Undefined): 787*635a8641SAndroid Build Coastguard Worker """An undefined that barks on print and iteration as well as boolean 788*635a8641SAndroid Build Coastguard Worker tests and all kinds of comparisons. In other words: you can do nothing 789*635a8641SAndroid Build Coastguard Worker with it except checking if it's defined using the `defined` test. 790*635a8641SAndroid Build Coastguard Worker 791*635a8641SAndroid Build Coastguard Worker >>> foo = StrictUndefined(name='foo') 792*635a8641SAndroid Build Coastguard Worker >>> str(foo) 793*635a8641SAndroid Build Coastguard Worker Traceback (most recent call last): 794*635a8641SAndroid Build Coastguard Worker ... 795*635a8641SAndroid Build Coastguard Worker jinja2.exceptions.UndefinedError: 'foo' is undefined 796*635a8641SAndroid Build Coastguard Worker >>> not foo 797*635a8641SAndroid Build Coastguard Worker Traceback (most recent call last): 798*635a8641SAndroid Build Coastguard Worker ... 799*635a8641SAndroid Build Coastguard Worker jinja2.exceptions.UndefinedError: 'foo' is undefined 800*635a8641SAndroid Build Coastguard Worker >>> foo + 42 801*635a8641SAndroid Build Coastguard Worker Traceback (most recent call last): 802*635a8641SAndroid Build Coastguard Worker ... 803*635a8641SAndroid Build Coastguard Worker jinja2.exceptions.UndefinedError: 'foo' is undefined 804*635a8641SAndroid Build Coastguard Worker """ 805*635a8641SAndroid Build Coastguard Worker __slots__ = () 806*635a8641SAndroid Build Coastguard Worker __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \ 807*635a8641SAndroid Build Coastguard Worker __ne__ = __bool__ = __hash__ = \ 808*635a8641SAndroid Build Coastguard Worker Undefined._fail_with_undefined_error 809*635a8641SAndroid Build Coastguard Worker 810*635a8641SAndroid Build Coastguard Worker 811*635a8641SAndroid Build Coastguard Worker# remove remaining slots attributes, after the metaclass did the magic they 812*635a8641SAndroid Build Coastguard Worker# are unneeded and irritating as they contain wrong data for the subclasses. 813*635a8641SAndroid Build Coastguard Workerdel Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__ 814