1# -*- coding: utf-8 -*- 2""" 3 jinja2.runtime 4 ~~~~~~~~~~~~~~ 5 6 Runtime helpers. 7 8 :copyright: (c) 2010 by the Jinja Team. 9 :license: BSD. 10""" 11import sys 12from itertools import chain, imap 13from jinja2.nodes import EvalContext 14from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \ 15 concat, MethodType, FunctionType, internalcode, next, \ 16 object_type_repr 17from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ 18 TemplateNotFound 19 20 21# these variables are exported to the template runtime 22__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup', 23 'TemplateRuntimeError', 'missing', 'concat', 'escape', 24 'markup_join', 'unicode_join', 'to_string', 25 'TemplateNotFound'] 26 27 28#: the types we support for context functions 29_context_function_types = (FunctionType, MethodType) 30 31#: the name of the function that is used to convert something into 32#: a string. 2to3 will adopt that automatically and the generated 33#: code can take advantage of it. 34to_string = unicode 35 36 37def markup_join(seq): 38 """Concatenation that escapes if necessary and converts to unicode.""" 39 buf = [] 40 iterator = imap(soft_unicode, seq) 41 for arg in iterator: 42 buf.append(arg) 43 if hasattr(arg, '__html__'): 44 return Markup(u'').join(chain(buf, iterator)) 45 return concat(buf) 46 47 48def unicode_join(seq): 49 """Simple args to unicode conversion and concatenation.""" 50 return concat(imap(unicode, seq)) 51 52 53def new_context(environment, template_name, blocks, vars=None, 54 shared=None, globals=None, locals=None): 55 """Internal helper to for context creation.""" 56 if vars is None: 57 vars = {} 58 if shared: 59 parent = vars 60 else: 61 parent = dict(globals or (), **vars) 62 if locals: 63 # if the parent is shared a copy should be created because 64 # we don't want to modify the dict passed 65 if shared: 66 parent = dict(parent) 67 for key, value in locals.iteritems(): 68 if key[:2] == 'l_' and value is not missing: 69 parent[key[2:]] = value 70 return Context(environment, parent, template_name, blocks) 71 72 73class TemplateReference(object): 74 """The `self` in templates.""" 75 76 def __init__(self, context): 77 self.__context = context 78 79 def __getitem__(self, name): 80 blocks = self.__context.blocks[name] 81 wrap = self.__context.eval_ctx.autoescape and \ 82 Markup or (lambda x: x) 83 return BlockReference(name, self.__context, blocks, 0) 84 85 def __repr__(self): 86 return '<%s %r>' % ( 87 self.__class__.__name__, 88 self.__context.name 89 ) 90 91 92class Context(object): 93 """The template context holds the variables of a template. It stores the 94 values passed to the template and also the names the template exports. 95 Creating instances is neither supported nor useful as it's created 96 automatically at various stages of the template evaluation and should not 97 be created by hand. 98 99 The context is immutable. Modifications on :attr:`parent` **must not** 100 happen and modifications on :attr:`vars` are allowed from generated 101 template code only. Template filters and global functions marked as 102 :func:`contextfunction`\s get the active context passed as first argument 103 and are allowed to access the context read-only. 104 105 The template context supports read only dict operations (`get`, 106 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`, 107 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve` 108 method that doesn't fail with a `KeyError` but returns an 109 :class:`Undefined` object for missing variables. 110 """ 111 __slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars', 112 'name', 'blocks', '__weakref__') 113 114 def __init__(self, environment, parent, name, blocks): 115 self.parent = parent 116 self.vars = {} 117 self.environment = environment 118 self.eval_ctx = EvalContext(self.environment, name) 119 self.exported_vars = set() 120 self.name = name 121 122 # create the initial mapping of blocks. Whenever template inheritance 123 # takes place the runtime will update this mapping with the new blocks 124 # from the template. 125 self.blocks = dict((k, [v]) for k, v in blocks.iteritems()) 126 127 def super(self, name, current): 128 """Render a parent block.""" 129 try: 130 blocks = self.blocks[name] 131 index = blocks.index(current) + 1 132 blocks[index] 133 except LookupError: 134 return self.environment.undefined('there is no parent block ' 135 'called %r.' % name, 136 name='super') 137 return BlockReference(name, self, blocks, index) 138 139 def get(self, key, default=None): 140 """Returns an item from the template context, if it doesn't exist 141 `default` is returned. 142 """ 143 try: 144 return self[key] 145 except KeyError: 146 return default 147 148 def resolve(self, key): 149 """Looks up a variable like `__getitem__` or `get` but returns an 150 :class:`Undefined` object with the name of the name looked up. 151 """ 152 if key in self.vars: 153 return self.vars[key] 154 if key in self.parent: 155 return self.parent[key] 156 return self.environment.undefined(name=key) 157 158 def get_exported(self): 159 """Get a new dict with the exported variables.""" 160 return dict((k, self.vars[k]) for k in self.exported_vars) 161 162 def get_all(self): 163 """Return a copy of the complete context as dict including the 164 exported variables. 165 """ 166 return dict(self.parent, **self.vars) 167 168 @internalcode 169 def call(__self, __obj, *args, **kwargs): 170 """Call the callable with the arguments and keyword arguments 171 provided but inject the active context or environment as first 172 argument if the callable is a :func:`contextfunction` or 173 :func:`environmentfunction`. 174 """ 175 if __debug__: 176 __traceback_hide__ = True 177 if isinstance(__obj, _context_function_types): 178 if getattr(__obj, 'contextfunction', 0): 179 args = (__self,) + args 180 elif getattr(__obj, 'evalcontextfunction', 0): 181 args = (__self.eval_ctx,) + args 182 elif getattr(__obj, 'environmentfunction', 0): 183 args = (__self.environment,) + args 184 return __obj(*args, **kwargs) 185 186 def derived(self, locals=None): 187 """Internal helper function to create a derived context.""" 188 context = new_context(self.environment, self.name, {}, 189 self.parent, True, None, locals) 190 context.eval_ctx = self.eval_ctx 191 context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems()) 192 return context 193 194 def _all(meth): 195 proxy = lambda self: getattr(self.get_all(), meth)() 196 proxy.__doc__ = getattr(dict, meth).__doc__ 197 proxy.__name__ = meth 198 return proxy 199 200 keys = _all('keys') 201 values = _all('values') 202 items = _all('items') 203 204 # not available on python 3 205 if hasattr(dict, 'iterkeys'): 206 iterkeys = _all('iterkeys') 207 itervalues = _all('itervalues') 208 iteritems = _all('iteritems') 209 del _all 210 211 def __contains__(self, name): 212 return name in self.vars or name in self.parent 213 214 def __getitem__(self, key): 215 """Lookup a variable or raise `KeyError` if the variable is 216 undefined. 217 """ 218 item = self.resolve(key) 219 if isinstance(item, Undefined): 220 raise KeyError(key) 221 return item 222 223 def __repr__(self): 224 return '<%s %s of %r>' % ( 225 self.__class__.__name__, 226 repr(self.get_all()), 227 self.name 228 ) 229 230 231# register the context as mapping if possible 232try: 233 from collections import Mapping 234 Mapping.register(Context) 235except ImportError: 236 pass 237 238 239class BlockReference(object): 240 """One block on a template reference.""" 241 242 def __init__(self, name, context, stack, depth): 243 self.name = name 244 self._context = context 245 self._stack = stack 246 self._depth = depth 247 248 @property 249 def super(self): 250 """Super the block.""" 251 if self._depth + 1 >= len(self._stack): 252 return self._context.environment. \ 253 undefined('there is no parent block called %r.' % 254 self.name, name='super') 255 return BlockReference(self.name, self._context, self._stack, 256 self._depth + 1) 257 258 @internalcode 259 def __call__(self): 260 rv = concat(self._stack[self._depth](self._context)) 261 if self._context.eval_ctx.autoescape: 262 rv = Markup(rv) 263 return rv 264 265 266class LoopContext(object): 267 """A loop context for dynamic iteration.""" 268 269 def __init__(self, iterable, recurse=None): 270 self._iterator = iter(iterable) 271 self._recurse = recurse 272 self.index0 = -1 273 274 # try to get the length of the iterable early. This must be done 275 # here because there are some broken iterators around where there 276 # __len__ is the number of iterations left (i'm looking at your 277 # listreverseiterator!). 278 try: 279 self._length = len(iterable) 280 except (TypeError, AttributeError): 281 self._length = None 282 283 def cycle(self, *args): 284 """Cycles among the arguments with the current loop index.""" 285 if not args: 286 raise TypeError('no items for cycling given') 287 return args[self.index0 % len(args)] 288 289 first = property(lambda x: x.index0 == 0) 290 last = property(lambda x: x.index0 + 1 == x.length) 291 index = property(lambda x: x.index0 + 1) 292 revindex = property(lambda x: x.length - x.index0) 293 revindex0 = property(lambda x: x.length - x.index) 294 295 def __len__(self): 296 return self.length 297 298 def __iter__(self): 299 return LoopContextIterator(self) 300 301 @internalcode 302 def loop(self, iterable): 303 if self._recurse is None: 304 raise TypeError('Tried to call non recursive loop. Maybe you ' 305 "forgot the 'recursive' modifier.") 306 return self._recurse(iterable, self._recurse) 307 308 # a nifty trick to enhance the error message if someone tried to call 309 # the the loop without or with too many arguments. 310 __call__ = loop 311 del loop 312 313 @property 314 def length(self): 315 if self._length is None: 316 # if was not possible to get the length of the iterator when 317 # the loop context was created (ie: iterating over a generator) 318 # we have to convert the iterable into a sequence and use the 319 # length of that. 320 iterable = tuple(self._iterator) 321 self._iterator = iter(iterable) 322 self._length = len(iterable) + self.index0 + 1 323 return self._length 324 325 def __repr__(self): 326 return '<%s %r/%r>' % ( 327 self.__class__.__name__, 328 self.index, 329 self.length 330 ) 331 332 333class LoopContextIterator(object): 334 """The iterator for a loop context.""" 335 __slots__ = ('context',) 336 337 def __init__(self, context): 338 self.context = context 339 340 def __iter__(self): 341 return self 342 343 def next(self): 344 ctx = self.context 345 ctx.index0 += 1 346 return next(ctx._iterator), ctx 347 348 349class Macro(object): 350 """Wraps a macro.""" 351 352 def __init__(self, environment, func, name, arguments, defaults, 353 catch_kwargs, catch_varargs, caller): 354 self._environment = environment 355 self._func = func 356 self._argument_count = len(arguments) 357 self.name = name 358 self.arguments = arguments 359 self.defaults = defaults 360 self.catch_kwargs = catch_kwargs 361 self.catch_varargs = catch_varargs 362 self.caller = caller 363 364 @internalcode 365 def __call__(self, *args, **kwargs): 366 arguments = [] 367 for idx, name in enumerate(self.arguments): 368 try: 369 value = args[idx] 370 except: 371 try: 372 value = kwargs.pop(name) 373 except: 374 try: 375 value = self.defaults[idx - self._argument_count] 376 except: 377 value = self._environment.undefined( 378 'parameter %r was not provided' % name, name=name) 379 arguments.append(value) 380 381 # it's important that the order of these arguments does not change 382 # if not also changed in the compiler's `function_scoping` method. 383 # the order is caller, keyword arguments, positional arguments! 384 if self.caller: 385 caller = kwargs.pop('caller', None) 386 if caller is None: 387 caller = self._environment.undefined('No caller defined', 388 name='caller') 389 arguments.append(caller) 390 if self.catch_kwargs: 391 arguments.append(kwargs) 392 elif kwargs: 393 raise TypeError('macro %r takes no keyword argument %r' % 394 (self.name, next(iter(kwargs)))) 395 if self.catch_varargs: 396 arguments.append(args[self._argument_count:]) 397 elif len(args) > self._argument_count: 398 raise TypeError('macro %r takes not more than %d argument(s)' % 399 (self.name, len(self.arguments))) 400 return self._func(*arguments) 401 402 def __repr__(self): 403 return '<%s %s>' % ( 404 self.__class__.__name__, 405 self.name is None and 'anonymous' or repr(self.name) 406 ) 407 408 409class Undefined(object): 410 """The default undefined type. This undefined type can be printed and 411 iterated over, but every other access will raise an :exc:`UndefinedError`: 412 413 >>> foo = Undefined(name='foo') 414 >>> str(foo) 415 '' 416 >>> not foo 417 True 418 >>> foo + 42 419 Traceback (most recent call last): 420 ... 421 UndefinedError: 'foo' is undefined 422 """ 423 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name', 424 '_undefined_exception') 425 426 def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): 427 self._undefined_hint = hint 428 self._undefined_obj = obj 429 self._undefined_name = name 430 self._undefined_exception = exc 431 432 @internalcode 433 def _fail_with_undefined_error(self, *args, **kwargs): 434 """Regular callback function for undefined objects that raises an 435 `UndefinedError` on call. 436 """ 437 if self._undefined_hint is None: 438 if self._undefined_obj is missing: 439 hint = '%r is undefined' % self._undefined_name 440 elif not isinstance(self._undefined_name, basestring): 441 hint = '%s has no element %r' % ( 442 object_type_repr(self._undefined_obj), 443 self._undefined_name 444 ) 445 else: 446 hint = '%r has no attribute %r' % ( 447 object_type_repr(self._undefined_obj), 448 self._undefined_name 449 ) 450 else: 451 hint = self._undefined_hint 452 raise self._undefined_exception(hint) 453 454 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \ 455 __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \ 456 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \ 457 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \ 458 __int__ = __float__ = __complex__ = __pow__ = __rpow__ = \ 459 _fail_with_undefined_error 460 461 def __str__(self): 462 return unicode(self).encode('utf-8') 463 464 # unicode goes after __str__ because we configured 2to3 to rename 465 # __unicode__ to __str__. because the 2to3 tree is not designed to 466 # remove nodes from it, we leave the above __str__ around and let 467 # it override at runtime. 468 def __unicode__(self): 469 return u'' 470 471 def __len__(self): 472 return 0 473 474 def __iter__(self): 475 if 0: 476 yield None 477 478 def __nonzero__(self): 479 return False 480 481 def __repr__(self): 482 return 'Undefined' 483 484 485class DebugUndefined(Undefined): 486 """An undefined that returns the debug info when printed. 487 488 >>> foo = DebugUndefined(name='foo') 489 >>> str(foo) 490 '{{ foo }}' 491 >>> not foo 492 True 493 >>> foo + 42 494 Traceback (most recent call last): 495 ... 496 UndefinedError: 'foo' is undefined 497 """ 498 __slots__ = () 499 500 def __unicode__(self): 501 if self._undefined_hint is None: 502 if self._undefined_obj is missing: 503 return u'{{ %s }}' % self._undefined_name 504 return '{{ no such element: %s[%r] }}' % ( 505 object_type_repr(self._undefined_obj), 506 self._undefined_name 507 ) 508 return u'{{ undefined value printed: %s }}' % self._undefined_hint 509 510 511class StrictUndefined(Undefined): 512 """An undefined that barks on print and iteration as well as boolean 513 tests and all kinds of comparisons. In other words: you can do nothing 514 with it except checking if it's defined using the `defined` test. 515 516 >>> foo = StrictUndefined(name='foo') 517 >>> str(foo) 518 Traceback (most recent call last): 519 ... 520 UndefinedError: 'foo' is undefined 521 >>> not foo 522 Traceback (most recent call last): 523 ... 524 UndefinedError: 'foo' is undefined 525 >>> foo + 42 526 Traceback (most recent call last): 527 ... 528 UndefinedError: 'foo' is undefined 529 """ 530 __slots__ = () 531 __iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \ 532 __ne__ = Undefined._fail_with_undefined_error 533 534 535# remove remaining slots attributes, after the metaclass did the magic they 536# are unneeded and irritating as they contain wrong data for the subclasses. 537del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__ 538