Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/jinja2/runtime.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
| author | shellac |
|---|---|
| date | Thu, 14 May 2020 14:56:58 -0400 |
| parents | 26e78fe6e8c4 |
| children |
comparison
equal
deleted
inserted
replaced
| 1:75ca89e9b81c | 2:6af9afd405e9 |
|---|---|
| 1 # -*- coding: utf-8 -*- | |
| 2 """The runtime functions and state used by compiled templates.""" | |
| 3 import sys | |
| 4 from itertools import chain | |
| 5 from types import MethodType | |
| 6 | |
| 7 from markupsafe import escape # noqa: F401 | |
| 8 from markupsafe import Markup | |
| 9 from markupsafe import soft_unicode | |
| 10 | |
| 11 from ._compat import abc | |
| 12 from ._compat import imap | |
| 13 from ._compat import implements_iterator | |
| 14 from ._compat import implements_to_string | |
| 15 from ._compat import iteritems | |
| 16 from ._compat import PY2 | |
| 17 from ._compat import string_types | |
| 18 from ._compat import text_type | |
| 19 from ._compat import with_metaclass | |
| 20 from .exceptions import TemplateNotFound # noqa: F401 | |
| 21 from .exceptions import TemplateRuntimeError # noqa: F401 | |
| 22 from .exceptions import UndefinedError | |
| 23 from .nodes import EvalContext | |
| 24 from .utils import concat | |
| 25 from .utils import evalcontextfunction | |
| 26 from .utils import internalcode | |
| 27 from .utils import missing | |
| 28 from .utils import Namespace # noqa: F401 | |
| 29 from .utils import object_type_repr | |
| 30 | |
| 31 # these variables are exported to the template runtime | |
| 32 exported = [ | |
| 33 "LoopContext", | |
| 34 "TemplateReference", | |
| 35 "Macro", | |
| 36 "Markup", | |
| 37 "TemplateRuntimeError", | |
| 38 "missing", | |
| 39 "concat", | |
| 40 "escape", | |
| 41 "markup_join", | |
| 42 "unicode_join", | |
| 43 "to_string", | |
| 44 "identity", | |
| 45 "TemplateNotFound", | |
| 46 "Namespace", | |
| 47 "Undefined", | |
| 48 ] | |
| 49 | |
| 50 #: the name of the function that is used to convert something into | |
| 51 #: a string. We can just use the text type here. | |
| 52 to_string = text_type | |
| 53 | |
| 54 | |
| 55 def identity(x): | |
| 56 """Returns its argument. Useful for certain things in the | |
| 57 environment. | |
| 58 """ | |
| 59 return x | |
| 60 | |
| 61 | |
| 62 def markup_join(seq): | |
| 63 """Concatenation that escapes if necessary and converts to unicode.""" | |
| 64 buf = [] | |
| 65 iterator = imap(soft_unicode, seq) | |
| 66 for arg in iterator: | |
| 67 buf.append(arg) | |
| 68 if hasattr(arg, "__html__"): | |
| 69 return Markup(u"").join(chain(buf, iterator)) | |
| 70 return concat(buf) | |
| 71 | |
| 72 | |
| 73 def unicode_join(seq): | |
| 74 """Simple args to unicode conversion and concatenation.""" | |
| 75 return concat(imap(text_type, seq)) | |
| 76 | |
| 77 | |
| 78 def new_context( | |
| 79 environment, | |
| 80 template_name, | |
| 81 blocks, | |
| 82 vars=None, | |
| 83 shared=None, | |
| 84 globals=None, | |
| 85 locals=None, | |
| 86 ): | |
| 87 """Internal helper for context creation.""" | |
| 88 if vars is None: | |
| 89 vars = {} | |
| 90 if shared: | |
| 91 parent = vars | |
| 92 else: | |
| 93 parent = dict(globals or (), **vars) | |
| 94 if locals: | |
| 95 # if the parent is shared a copy should be created because | |
| 96 # we don't want to modify the dict passed | |
| 97 if shared: | |
| 98 parent = dict(parent) | |
| 99 for key, value in iteritems(locals): | |
| 100 if value is not missing: | |
| 101 parent[key] = value | |
| 102 return environment.context_class(environment, parent, template_name, blocks) | |
| 103 | |
| 104 | |
| 105 class TemplateReference(object): | |
| 106 """The `self` in templates.""" | |
| 107 | |
| 108 def __init__(self, context): | |
| 109 self.__context = context | |
| 110 | |
| 111 def __getitem__(self, name): | |
| 112 blocks = self.__context.blocks[name] | |
| 113 return BlockReference(name, self.__context, blocks, 0) | |
| 114 | |
| 115 def __repr__(self): | |
| 116 return "<%s %r>" % (self.__class__.__name__, self.__context.name) | |
| 117 | |
| 118 | |
| 119 def _get_func(x): | |
| 120 return getattr(x, "__func__", x) | |
| 121 | |
| 122 | |
| 123 class ContextMeta(type): | |
| 124 def __new__(mcs, name, bases, d): | |
| 125 rv = type.__new__(mcs, name, bases, d) | |
| 126 if bases == (): | |
| 127 return rv | |
| 128 | |
| 129 resolve = _get_func(rv.resolve) | |
| 130 default_resolve = _get_func(Context.resolve) | |
| 131 resolve_or_missing = _get_func(rv.resolve_or_missing) | |
| 132 default_resolve_or_missing = _get_func(Context.resolve_or_missing) | |
| 133 | |
| 134 # If we have a changed resolve but no changed default or missing | |
| 135 # resolve we invert the call logic. | |
| 136 if ( | |
| 137 resolve is not default_resolve | |
| 138 and resolve_or_missing is default_resolve_or_missing | |
| 139 ): | |
| 140 rv._legacy_resolve_mode = True | |
| 141 elif ( | |
| 142 resolve is default_resolve | |
| 143 and resolve_or_missing is default_resolve_or_missing | |
| 144 ): | |
| 145 rv._fast_resolve_mode = True | |
| 146 | |
| 147 return rv | |
| 148 | |
| 149 | |
| 150 def resolve_or_missing(context, key, missing=missing): | |
| 151 if key in context.vars: | |
| 152 return context.vars[key] | |
| 153 if key in context.parent: | |
| 154 return context.parent[key] | |
| 155 return missing | |
| 156 | |
| 157 | |
| 158 class Context(with_metaclass(ContextMeta)): | |
| 159 """The template context holds the variables of a template. It stores the | |
| 160 values passed to the template and also the names the template exports. | |
| 161 Creating instances is neither supported nor useful as it's created | |
| 162 automatically at various stages of the template evaluation and should not | |
| 163 be created by hand. | |
| 164 | |
| 165 The context is immutable. Modifications on :attr:`parent` **must not** | |
| 166 happen and modifications on :attr:`vars` are allowed from generated | |
| 167 template code only. Template filters and global functions marked as | |
| 168 :func:`contextfunction`\\s get the active context passed as first argument | |
| 169 and are allowed to access the context read-only. | |
| 170 | |
| 171 The template context supports read only dict operations (`get`, | |
| 172 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`, | |
| 173 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve` | |
| 174 method that doesn't fail with a `KeyError` but returns an | |
| 175 :class:`Undefined` object for missing variables. | |
| 176 """ | |
| 177 | |
| 178 # XXX: we want to eventually make this be a deprecation warning and | |
| 179 # remove it. | |
| 180 _legacy_resolve_mode = False | |
| 181 _fast_resolve_mode = False | |
| 182 | |
| 183 def __init__(self, environment, parent, name, blocks): | |
| 184 self.parent = parent | |
| 185 self.vars = {} | |
| 186 self.environment = environment | |
| 187 self.eval_ctx = EvalContext(self.environment, name) | |
| 188 self.exported_vars = set() | |
| 189 self.name = name | |
| 190 | |
| 191 # create the initial mapping of blocks. Whenever template inheritance | |
| 192 # takes place the runtime will update this mapping with the new blocks | |
| 193 # from the template. | |
| 194 self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) | |
| 195 | |
| 196 # In case we detect the fast resolve mode we can set up an alias | |
| 197 # here that bypasses the legacy code logic. | |
| 198 if self._fast_resolve_mode: | |
| 199 self.resolve_or_missing = MethodType(resolve_or_missing, self) | |
| 200 | |
| 201 def super(self, name, current): | |
| 202 """Render a parent block.""" | |
| 203 try: | |
| 204 blocks = self.blocks[name] | |
| 205 index = blocks.index(current) + 1 | |
| 206 blocks[index] | |
| 207 except LookupError: | |
| 208 return self.environment.undefined( | |
| 209 "there is no parent block called %r." % name, name="super" | |
| 210 ) | |
| 211 return BlockReference(name, self, blocks, index) | |
| 212 | |
| 213 def get(self, key, default=None): | |
| 214 """Returns an item from the template context, if it doesn't exist | |
| 215 `default` is returned. | |
| 216 """ | |
| 217 try: | |
| 218 return self[key] | |
| 219 except KeyError: | |
| 220 return default | |
| 221 | |
| 222 def resolve(self, key): | |
| 223 """Looks up a variable like `__getitem__` or `get` but returns an | |
| 224 :class:`Undefined` object with the name of the name looked up. | |
| 225 """ | |
| 226 if self._legacy_resolve_mode: | |
| 227 rv = resolve_or_missing(self, key) | |
| 228 else: | |
| 229 rv = self.resolve_or_missing(key) | |
| 230 if rv is missing: | |
| 231 return self.environment.undefined(name=key) | |
| 232 return rv | |
| 233 | |
| 234 def resolve_or_missing(self, key): | |
| 235 """Resolves a variable like :meth:`resolve` but returns the | |
| 236 special `missing` value if it cannot be found. | |
| 237 """ | |
| 238 if self._legacy_resolve_mode: | |
| 239 rv = self.resolve(key) | |
| 240 if isinstance(rv, Undefined): | |
| 241 rv = missing | |
| 242 return rv | |
| 243 return resolve_or_missing(self, key) | |
| 244 | |
| 245 def get_exported(self): | |
| 246 """Get a new dict with the exported variables.""" | |
| 247 return dict((k, self.vars[k]) for k in self.exported_vars) | |
| 248 | |
| 249 def get_all(self): | |
| 250 """Return the complete context as dict including the exported | |
| 251 variables. For optimizations reasons this might not return an | |
| 252 actual copy so be careful with using it. | |
| 253 """ | |
| 254 if not self.vars: | |
| 255 return self.parent | |
| 256 if not self.parent: | |
| 257 return self.vars | |
| 258 return dict(self.parent, **self.vars) | |
| 259 | |
| 260 @internalcode | |
| 261 def call(__self, __obj, *args, **kwargs): # noqa: B902 | |
| 262 """Call the callable with the arguments and keyword arguments | |
| 263 provided but inject the active context or environment as first | |
| 264 argument if the callable is a :func:`contextfunction` or | |
| 265 :func:`environmentfunction`. | |
| 266 """ | |
| 267 if __debug__: | |
| 268 __traceback_hide__ = True # noqa | |
| 269 | |
| 270 # Allow callable classes to take a context | |
| 271 if hasattr(__obj, "__call__"): # noqa: B004 | |
| 272 fn = __obj.__call__ | |
| 273 for fn_type in ( | |
| 274 "contextfunction", | |
| 275 "evalcontextfunction", | |
| 276 "environmentfunction", | |
| 277 ): | |
| 278 if hasattr(fn, fn_type): | |
| 279 __obj = fn | |
| 280 break | |
| 281 | |
| 282 if callable(__obj): | |
| 283 if getattr(__obj, "contextfunction", False) is True: | |
| 284 args = (__self,) + args | |
| 285 elif getattr(__obj, "evalcontextfunction", False) is True: | |
| 286 args = (__self.eval_ctx,) + args | |
| 287 elif getattr(__obj, "environmentfunction", False) is True: | |
| 288 args = (__self.environment,) + args | |
| 289 try: | |
| 290 return __obj(*args, **kwargs) | |
| 291 except StopIteration: | |
| 292 return __self.environment.undefined( | |
| 293 "value was undefined because " | |
| 294 "a callable raised a " | |
| 295 "StopIteration exception" | |
| 296 ) | |
| 297 | |
| 298 def derived(self, locals=None): | |
| 299 """Internal helper function to create a derived context. This is | |
| 300 used in situations where the system needs a new context in the same | |
| 301 template that is independent. | |
| 302 """ | |
| 303 context = new_context( | |
| 304 self.environment, self.name, {}, self.get_all(), True, None, locals | |
| 305 ) | |
| 306 context.eval_ctx = self.eval_ctx | |
| 307 context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) | |
| 308 return context | |
| 309 | |
| 310 def _all(meth): # noqa: B902 | |
| 311 def proxy(self): | |
| 312 return getattr(self.get_all(), meth)() | |
| 313 | |
| 314 proxy.__doc__ = getattr(dict, meth).__doc__ | |
| 315 proxy.__name__ = meth | |
| 316 return proxy | |
| 317 | |
| 318 keys = _all("keys") | |
| 319 values = _all("values") | |
| 320 items = _all("items") | |
| 321 | |
| 322 # not available on python 3 | |
| 323 if PY2: | |
| 324 iterkeys = _all("iterkeys") | |
| 325 itervalues = _all("itervalues") | |
| 326 iteritems = _all("iteritems") | |
| 327 del _all | |
| 328 | |
| 329 def __contains__(self, name): | |
| 330 return name in self.vars or name in self.parent | |
| 331 | |
| 332 def __getitem__(self, key): | |
| 333 """Lookup a variable or raise `KeyError` if the variable is | |
| 334 undefined. | |
| 335 """ | |
| 336 item = self.resolve_or_missing(key) | |
| 337 if item is missing: | |
| 338 raise KeyError(key) | |
| 339 return item | |
| 340 | |
| 341 def __repr__(self): | |
| 342 return "<%s %s of %r>" % ( | |
| 343 self.__class__.__name__, | |
| 344 repr(self.get_all()), | |
| 345 self.name, | |
| 346 ) | |
| 347 | |
| 348 | |
| 349 abc.Mapping.register(Context) | |
| 350 | |
| 351 | |
| 352 class BlockReference(object): | |
| 353 """One block on a template reference.""" | |
| 354 | |
| 355 def __init__(self, name, context, stack, depth): | |
| 356 self.name = name | |
| 357 self._context = context | |
| 358 self._stack = stack | |
| 359 self._depth = depth | |
| 360 | |
| 361 @property | |
| 362 def super(self): | |
| 363 """Super the block.""" | |
| 364 if self._depth + 1 >= len(self._stack): | |
| 365 return self._context.environment.undefined( | |
| 366 "there is no parent block called %r." % self.name, name="super" | |
| 367 ) | |
| 368 return BlockReference(self.name, self._context, self._stack, self._depth + 1) | |
| 369 | |
| 370 @internalcode | |
| 371 def __call__(self): | |
| 372 rv = concat(self._stack[self._depth](self._context)) | |
| 373 if self._context.eval_ctx.autoescape: | |
| 374 rv = Markup(rv) | |
| 375 return rv | |
| 376 | |
| 377 | |
| 378 @implements_iterator | |
| 379 class LoopContext: | |
| 380 """A wrapper iterable for dynamic ``for`` loops, with information | |
| 381 about the loop and iteration. | |
| 382 """ | |
| 383 | |
| 384 #: Current iteration of the loop, starting at 0. | |
| 385 index0 = -1 | |
| 386 | |
| 387 _length = None | |
| 388 _after = missing | |
| 389 _current = missing | |
| 390 _before = missing | |
| 391 _last_changed_value = missing | |
| 392 | |
| 393 def __init__(self, iterable, undefined, recurse=None, depth0=0): | |
| 394 """ | |
| 395 :param iterable: Iterable to wrap. | |
| 396 :param undefined: :class:`Undefined` class to use for next and | |
| 397 previous items. | |
| 398 :param recurse: The function to render the loop body when the | |
| 399 loop is marked recursive. | |
| 400 :param depth0: Incremented when looping recursively. | |
| 401 """ | |
| 402 self._iterable = iterable | |
| 403 self._iterator = self._to_iterator(iterable) | |
| 404 self._undefined = undefined | |
| 405 self._recurse = recurse | |
| 406 #: How many levels deep a recursive loop currently is, starting at 0. | |
| 407 self.depth0 = depth0 | |
| 408 | |
| 409 @staticmethod | |
| 410 def _to_iterator(iterable): | |
| 411 return iter(iterable) | |
| 412 | |
| 413 @property | |
| 414 def length(self): | |
| 415 """Length of the iterable. | |
| 416 | |
| 417 If the iterable is a generator or otherwise does not have a | |
| 418 size, it is eagerly evaluated to get a size. | |
| 419 """ | |
| 420 if self._length is not None: | |
| 421 return self._length | |
| 422 | |
| 423 try: | |
| 424 self._length = len(self._iterable) | |
| 425 except TypeError: | |
| 426 iterable = list(self._iterator) | |
| 427 self._iterator = self._to_iterator(iterable) | |
| 428 self._length = len(iterable) + self.index + (self._after is not missing) | |
| 429 | |
| 430 return self._length | |
| 431 | |
| 432 def __len__(self): | |
| 433 return self.length | |
| 434 | |
| 435 @property | |
| 436 def depth(self): | |
| 437 """How many levels deep a recursive loop currently is, starting at 1.""" | |
| 438 return self.depth0 + 1 | |
| 439 | |
| 440 @property | |
| 441 def index(self): | |
| 442 """Current iteration of the loop, starting at 1.""" | |
| 443 return self.index0 + 1 | |
| 444 | |
| 445 @property | |
| 446 def revindex0(self): | |
| 447 """Number of iterations from the end of the loop, ending at 0. | |
| 448 | |
| 449 Requires calculating :attr:`length`. | |
| 450 """ | |
| 451 return self.length - self.index | |
| 452 | |
| 453 @property | |
| 454 def revindex(self): | |
| 455 """Number of iterations from the end of the loop, ending at 1. | |
| 456 | |
| 457 Requires calculating :attr:`length`. | |
| 458 """ | |
| 459 return self.length - self.index0 | |
| 460 | |
| 461 @property | |
| 462 def first(self): | |
| 463 """Whether this is the first iteration of the loop.""" | |
| 464 return self.index0 == 0 | |
| 465 | |
| 466 def _peek_next(self): | |
| 467 """Return the next element in the iterable, or :data:`missing` | |
| 468 if the iterable is exhausted. Only peeks one item ahead, caching | |
| 469 the result in :attr:`_last` for use in subsequent checks. The | |
| 470 cache is reset when :meth:`__next__` is called. | |
| 471 """ | |
| 472 if self._after is not missing: | |
| 473 return self._after | |
| 474 | |
| 475 self._after = next(self._iterator, missing) | |
| 476 return self._after | |
| 477 | |
| 478 @property | |
| 479 def last(self): | |
| 480 """Whether this is the last iteration of the loop. | |
| 481 | |
| 482 Causes the iterable to advance early. See | |
| 483 :func:`itertools.groupby` for issues this can cause. | |
| 484 The :func:`groupby` filter avoids that issue. | |
| 485 """ | |
| 486 return self._peek_next() is missing | |
| 487 | |
| 488 @property | |
| 489 def previtem(self): | |
| 490 """The item in the previous iteration. Undefined during the | |
| 491 first iteration. | |
| 492 """ | |
| 493 if self.first: | |
| 494 return self._undefined("there is no previous item") | |
| 495 | |
| 496 return self._before | |
| 497 | |
| 498 @property | |
| 499 def nextitem(self): | |
| 500 """The item in the next iteration. Undefined during the last | |
| 501 iteration. | |
| 502 | |
| 503 Causes the iterable to advance early. See | |
| 504 :func:`itertools.groupby` for issues this can cause. | |
| 505 The :func:`groupby` filter avoids that issue. | |
| 506 """ | |
| 507 rv = self._peek_next() | |
| 508 | |
| 509 if rv is missing: | |
| 510 return self._undefined("there is no next item") | |
| 511 | |
| 512 return rv | |
| 513 | |
| 514 def cycle(self, *args): | |
| 515 """Return a value from the given args, cycling through based on | |
| 516 the current :attr:`index0`. | |
| 517 | |
| 518 :param args: One or more values to cycle through. | |
| 519 """ | |
| 520 if not args: | |
| 521 raise TypeError("no items for cycling given") | |
| 522 | |
| 523 return args[self.index0 % len(args)] | |
| 524 | |
| 525 def changed(self, *value): | |
| 526 """Return ``True`` if previously called with a different value | |
| 527 (including when called for the first time). | |
| 528 | |
| 529 :param value: One or more values to compare to the last call. | |
| 530 """ | |
| 531 if self._last_changed_value != value: | |
| 532 self._last_changed_value = value | |
| 533 return True | |
| 534 | |
| 535 return False | |
| 536 | |
| 537 def __iter__(self): | |
| 538 return self | |
| 539 | |
| 540 def __next__(self): | |
| 541 if self._after is not missing: | |
| 542 rv = self._after | |
| 543 self._after = missing | |
| 544 else: | |
| 545 rv = next(self._iterator) | |
| 546 | |
| 547 self.index0 += 1 | |
| 548 self._before = self._current | |
| 549 self._current = rv | |
| 550 return rv, self | |
| 551 | |
| 552 @internalcode | |
| 553 def __call__(self, iterable): | |
| 554 """When iterating over nested data, render the body of the loop | |
| 555 recursively with the given inner iterable data. | |
| 556 | |
| 557 The loop must have the ``recursive`` marker for this to work. | |
| 558 """ | |
| 559 if self._recurse is None: | |
| 560 raise TypeError( | |
| 561 "The loop must have the 'recursive' marker to be called recursively." | |
| 562 ) | |
| 563 | |
| 564 return self._recurse(iterable, self._recurse, depth=self.depth) | |
| 565 | |
| 566 def __repr__(self): | |
| 567 return "<%s %d/%d>" % (self.__class__.__name__, self.index, self.length) | |
| 568 | |
| 569 | |
| 570 class Macro(object): | |
| 571 """Wraps a macro function.""" | |
| 572 | |
| 573 def __init__( | |
| 574 self, | |
| 575 environment, | |
| 576 func, | |
| 577 name, | |
| 578 arguments, | |
| 579 catch_kwargs, | |
| 580 catch_varargs, | |
| 581 caller, | |
| 582 default_autoescape=None, | |
| 583 ): | |
| 584 self._environment = environment | |
| 585 self._func = func | |
| 586 self._argument_count = len(arguments) | |
| 587 self.name = name | |
| 588 self.arguments = arguments | |
| 589 self.catch_kwargs = catch_kwargs | |
| 590 self.catch_varargs = catch_varargs | |
| 591 self.caller = caller | |
| 592 self.explicit_caller = "caller" in arguments | |
| 593 if default_autoescape is None: | |
| 594 default_autoescape = environment.autoescape | |
| 595 self._default_autoescape = default_autoescape | |
| 596 | |
| 597 @internalcode | |
| 598 @evalcontextfunction | |
| 599 def __call__(self, *args, **kwargs): | |
| 600 # This requires a bit of explanation, In the past we used to | |
| 601 # decide largely based on compile-time information if a macro is | |
| 602 # safe or unsafe. While there was a volatile mode it was largely | |
| 603 # unused for deciding on escaping. This turns out to be | |
| 604 # problematic for macros because whether a macro is safe depends not | |
| 605 # on the escape mode when it was defined, but rather when it was used. | |
| 606 # | |
| 607 # Because however we export macros from the module system and | |
| 608 # there are historic callers that do not pass an eval context (and | |
| 609 # will continue to not pass one), we need to perform an instance | |
| 610 # check here. | |
| 611 # | |
| 612 # This is considered safe because an eval context is not a valid | |
| 613 # argument to callables otherwise anyway. Worst case here is | |
| 614 # that if no eval context is passed we fall back to the compile | |
| 615 # time autoescape flag. | |
| 616 if args and isinstance(args[0], EvalContext): | |
| 617 autoescape = args[0].autoescape | |
| 618 args = args[1:] | |
| 619 else: | |
| 620 autoescape = self._default_autoescape | |
| 621 | |
| 622 # try to consume the positional arguments | |
| 623 arguments = list(args[: self._argument_count]) | |
| 624 off = len(arguments) | |
| 625 | |
| 626 # For information why this is necessary refer to the handling | |
| 627 # of caller in the `macro_body` handler in the compiler. | |
| 628 found_caller = False | |
| 629 | |
| 630 # if the number of arguments consumed is not the number of | |
| 631 # arguments expected we start filling in keyword arguments | |
| 632 # and defaults. | |
| 633 if off != self._argument_count: | |
| 634 for name in self.arguments[len(arguments) :]: | |
| 635 try: | |
| 636 value = kwargs.pop(name) | |
| 637 except KeyError: | |
| 638 value = missing | |
| 639 if name == "caller": | |
| 640 found_caller = True | |
| 641 arguments.append(value) | |
| 642 else: | |
| 643 found_caller = self.explicit_caller | |
| 644 | |
| 645 # it's important that the order of these arguments does not change | |
| 646 # if not also changed in the compiler's `function_scoping` method. | |
| 647 # the order is caller, keyword arguments, positional arguments! | |
| 648 if self.caller and not found_caller: | |
| 649 caller = kwargs.pop("caller", None) | |
| 650 if caller is None: | |
| 651 caller = self._environment.undefined("No caller defined", name="caller") | |
| 652 arguments.append(caller) | |
| 653 | |
| 654 if self.catch_kwargs: | |
| 655 arguments.append(kwargs) | |
| 656 elif kwargs: | |
| 657 if "caller" in kwargs: | |
| 658 raise TypeError( | |
| 659 "macro %r was invoked with two values for " | |
| 660 "the special caller argument. This is " | |
| 661 "most likely a bug." % self.name | |
| 662 ) | |
| 663 raise TypeError( | |
| 664 "macro %r takes no keyword argument %r" | |
| 665 % (self.name, next(iter(kwargs))) | |
| 666 ) | |
| 667 if self.catch_varargs: | |
| 668 arguments.append(args[self._argument_count :]) | |
| 669 elif len(args) > self._argument_count: | |
| 670 raise TypeError( | |
| 671 "macro %r takes not more than %d argument(s)" | |
| 672 % (self.name, len(self.arguments)) | |
| 673 ) | |
| 674 | |
| 675 return self._invoke(arguments, autoescape) | |
| 676 | |
| 677 def _invoke(self, arguments, autoescape): | |
| 678 """This method is being swapped out by the async implementation.""" | |
| 679 rv = self._func(*arguments) | |
| 680 if autoescape: | |
| 681 rv = Markup(rv) | |
| 682 return rv | |
| 683 | |
| 684 def __repr__(self): | |
| 685 return "<%s %s>" % ( | |
| 686 self.__class__.__name__, | |
| 687 self.name is None and "anonymous" or repr(self.name), | |
| 688 ) | |
| 689 | |
| 690 | |
| 691 @implements_to_string | |
| 692 class Undefined(object): | |
| 693 """The default undefined type. This undefined type can be printed and | |
| 694 iterated over, but every other access will raise an :exc:`UndefinedError`: | |
| 695 | |
| 696 >>> foo = Undefined(name='foo') | |
| 697 >>> str(foo) | |
| 698 '' | |
| 699 >>> not foo | |
| 700 True | |
| 701 >>> foo + 42 | |
| 702 Traceback (most recent call last): | |
| 703 ... | |
| 704 jinja2.exceptions.UndefinedError: 'foo' is undefined | |
| 705 """ | |
| 706 | |
| 707 __slots__ = ( | |
| 708 "_undefined_hint", | |
| 709 "_undefined_obj", | |
| 710 "_undefined_name", | |
| 711 "_undefined_exception", | |
| 712 ) | |
| 713 | |
| 714 def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): | |
| 715 self._undefined_hint = hint | |
| 716 self._undefined_obj = obj | |
| 717 self._undefined_name = name | |
| 718 self._undefined_exception = exc | |
| 719 | |
| 720 @property | |
| 721 def _undefined_message(self): | |
| 722 """Build a message about the undefined value based on how it was | |
| 723 accessed. | |
| 724 """ | |
| 725 if self._undefined_hint: | |
| 726 return self._undefined_hint | |
| 727 | |
| 728 if self._undefined_obj is missing: | |
| 729 return "%r is undefined" % self._undefined_name | |
| 730 | |
| 731 if not isinstance(self._undefined_name, string_types): | |
| 732 return "%s has no element %r" % ( | |
| 733 object_type_repr(self._undefined_obj), | |
| 734 self._undefined_name, | |
| 735 ) | |
| 736 | |
| 737 return "%r has no attribute %r" % ( | |
| 738 object_type_repr(self._undefined_obj), | |
| 739 self._undefined_name, | |
| 740 ) | |
| 741 | |
| 742 @internalcode | |
| 743 def _fail_with_undefined_error(self, *args, **kwargs): | |
| 744 """Raise an :exc:`UndefinedError` when operations are performed | |
| 745 on the undefined value. | |
| 746 """ | |
| 747 raise self._undefined_exception(self._undefined_message) | |
| 748 | |
| 749 @internalcode | |
| 750 def __getattr__(self, name): | |
| 751 if name[:2] == "__": | |
| 752 raise AttributeError(name) | |
| 753 return self._fail_with_undefined_error() | |
| 754 | |
| 755 __add__ = ( | |
| 756 __radd__ | |
| 757 ) = ( | |
| 758 __mul__ | |
| 759 ) = ( | |
| 760 __rmul__ | |
| 761 ) = ( | |
| 762 __div__ | |
| 763 ) = ( | |
| 764 __rdiv__ | |
| 765 ) = ( | |
| 766 __truediv__ | |
| 767 ) = ( | |
| 768 __rtruediv__ | |
| 769 ) = ( | |
| 770 __floordiv__ | |
| 771 ) = ( | |
| 772 __rfloordiv__ | |
| 773 ) = ( | |
| 774 __mod__ | |
| 775 ) = ( | |
| 776 __rmod__ | |
| 777 ) = ( | |
| 778 __pos__ | |
| 779 ) = ( | |
| 780 __neg__ | |
| 781 ) = ( | |
| 782 __call__ | |
| 783 ) = ( | |
| 784 __getitem__ | |
| 785 ) = ( | |
| 786 __lt__ | |
| 787 ) = ( | |
| 788 __le__ | |
| 789 ) = ( | |
| 790 __gt__ | |
| 791 ) = ( | |
| 792 __ge__ | |
| 793 ) = ( | |
| 794 __int__ | |
| 795 ) = ( | |
| 796 __float__ | |
| 797 ) = ( | |
| 798 __complex__ | |
| 799 ) = __pow__ = __rpow__ = __sub__ = __rsub__ = _fail_with_undefined_error | |
| 800 | |
| 801 def __eq__(self, other): | |
| 802 return type(self) is type(other) | |
| 803 | |
| 804 def __ne__(self, other): | |
| 805 return not self.__eq__(other) | |
| 806 | |
| 807 def __hash__(self): | |
| 808 return id(type(self)) | |
| 809 | |
| 810 def __str__(self): | |
| 811 return u"" | |
| 812 | |
| 813 def __len__(self): | |
| 814 return 0 | |
| 815 | |
| 816 def __iter__(self): | |
| 817 if 0: | |
| 818 yield None | |
| 819 | |
| 820 def __nonzero__(self): | |
| 821 return False | |
| 822 | |
| 823 __bool__ = __nonzero__ | |
| 824 | |
| 825 def __repr__(self): | |
| 826 return "Undefined" | |
| 827 | |
| 828 | |
| 829 def make_logging_undefined(logger=None, base=None): | |
| 830 """Given a logger object this returns a new undefined class that will | |
| 831 log certain failures. It will log iterations and printing. If no | |
| 832 logger is given a default logger is created. | |
| 833 | |
| 834 Example:: | |
| 835 | |
| 836 logger = logging.getLogger(__name__) | |
| 837 LoggingUndefined = make_logging_undefined( | |
| 838 logger=logger, | |
| 839 base=Undefined | |
| 840 ) | |
| 841 | |
| 842 .. versionadded:: 2.8 | |
| 843 | |
| 844 :param logger: the logger to use. If not provided, a default logger | |
| 845 is created. | |
| 846 :param base: the base class to add logging functionality to. This | |
| 847 defaults to :class:`Undefined`. | |
| 848 """ | |
| 849 if logger is None: | |
| 850 import logging | |
| 851 | |
| 852 logger = logging.getLogger(__name__) | |
| 853 logger.addHandler(logging.StreamHandler(sys.stderr)) | |
| 854 if base is None: | |
| 855 base = Undefined | |
| 856 | |
| 857 def _log_message(undef): | |
| 858 if undef._undefined_hint is None: | |
| 859 if undef._undefined_obj is missing: | |
| 860 hint = "%s is undefined" % undef._undefined_name | |
| 861 elif not isinstance(undef._undefined_name, string_types): | |
| 862 hint = "%s has no element %s" % ( | |
| 863 object_type_repr(undef._undefined_obj), | |
| 864 undef._undefined_name, | |
| 865 ) | |
| 866 else: | |
| 867 hint = "%s has no attribute %s" % ( | |
| 868 object_type_repr(undef._undefined_obj), | |
| 869 undef._undefined_name, | |
| 870 ) | |
| 871 else: | |
| 872 hint = undef._undefined_hint | |
| 873 logger.warning("Template variable warning: %s", hint) | |
| 874 | |
| 875 class LoggingUndefined(base): | |
| 876 def _fail_with_undefined_error(self, *args, **kwargs): | |
| 877 try: | |
| 878 return base._fail_with_undefined_error(self, *args, **kwargs) | |
| 879 except self._undefined_exception as e: | |
| 880 logger.error("Template variable error: %s", str(e)) | |
| 881 raise e | |
| 882 | |
| 883 def __str__(self): | |
| 884 rv = base.__str__(self) | |
| 885 _log_message(self) | |
| 886 return rv | |
| 887 | |
| 888 def __iter__(self): | |
| 889 rv = base.__iter__(self) | |
| 890 _log_message(self) | |
| 891 return rv | |
| 892 | |
| 893 if PY2: | |
| 894 | |
| 895 def __nonzero__(self): | |
| 896 rv = base.__nonzero__(self) | |
| 897 _log_message(self) | |
| 898 return rv | |
| 899 | |
| 900 def __unicode__(self): | |
| 901 rv = base.__unicode__(self) | |
| 902 _log_message(self) | |
| 903 return rv | |
| 904 | |
| 905 else: | |
| 906 | |
| 907 def __bool__(self): | |
| 908 rv = base.__bool__(self) | |
| 909 _log_message(self) | |
| 910 return rv | |
| 911 | |
| 912 return LoggingUndefined | |
| 913 | |
| 914 | |
| 915 # No @implements_to_string decorator here because __str__ | |
| 916 # is not overwritten from Undefined in this class. | |
| 917 # This would cause a recursion error in Python 2. | |
| 918 class ChainableUndefined(Undefined): | |
| 919 """An undefined that is chainable, where both ``__getattr__`` and | |
| 920 ``__getitem__`` return itself rather than raising an | |
| 921 :exc:`UndefinedError`. | |
| 922 | |
| 923 >>> foo = ChainableUndefined(name='foo') | |
| 924 >>> str(foo.bar['baz']) | |
| 925 '' | |
| 926 >>> foo.bar['baz'] + 42 | |
| 927 Traceback (most recent call last): | |
| 928 ... | |
| 929 jinja2.exceptions.UndefinedError: 'foo' is undefined | |
| 930 | |
| 931 .. versionadded:: 2.11.0 | |
| 932 """ | |
| 933 | |
| 934 __slots__ = () | |
| 935 | |
| 936 def __html__(self): | |
| 937 return self.__str__() | |
| 938 | |
| 939 def __getattr__(self, _): | |
| 940 return self | |
| 941 | |
| 942 __getitem__ = __getattr__ | |
| 943 | |
| 944 | |
| 945 @implements_to_string | |
| 946 class DebugUndefined(Undefined): | |
| 947 """An undefined that returns the debug info when printed. | |
| 948 | |
| 949 >>> foo = DebugUndefined(name='foo') | |
| 950 >>> str(foo) | |
| 951 '{{ foo }}' | |
| 952 >>> not foo | |
| 953 True | |
| 954 >>> foo + 42 | |
| 955 Traceback (most recent call last): | |
| 956 ... | |
| 957 jinja2.exceptions.UndefinedError: 'foo' is undefined | |
| 958 """ | |
| 959 | |
| 960 __slots__ = () | |
| 961 | |
| 962 def __str__(self): | |
| 963 if self._undefined_hint is None: | |
| 964 if self._undefined_obj is missing: | |
| 965 return u"{{ %s }}" % self._undefined_name | |
| 966 return "{{ no such element: %s[%r] }}" % ( | |
| 967 object_type_repr(self._undefined_obj), | |
| 968 self._undefined_name, | |
| 969 ) | |
| 970 return u"{{ undefined value printed: %s }}" % self._undefined_hint | |
| 971 | |
| 972 | |
| 973 @implements_to_string | |
| 974 class StrictUndefined(Undefined): | |
| 975 """An undefined that barks on print and iteration as well as boolean | |
| 976 tests and all kinds of comparisons. In other words: you can do nothing | |
| 977 with it except checking if it's defined using the `defined` test. | |
| 978 | |
| 979 >>> foo = StrictUndefined(name='foo') | |
| 980 >>> str(foo) | |
| 981 Traceback (most recent call last): | |
| 982 ... | |
| 983 jinja2.exceptions.UndefinedError: 'foo' is undefined | |
| 984 >>> not foo | |
| 985 Traceback (most recent call last): | |
| 986 ... | |
| 987 jinja2.exceptions.UndefinedError: 'foo' is undefined | |
| 988 >>> foo + 42 | |
| 989 Traceback (most recent call last): | |
| 990 ... | |
| 991 jinja2.exceptions.UndefinedError: 'foo' is undefined | |
| 992 """ | |
| 993 | |
| 994 __slots__ = () | |
| 995 __iter__ = ( | |
| 996 __str__ | |
| 997 ) = ( | |
| 998 __len__ | |
| 999 ) = ( | |
| 1000 __nonzero__ | |
| 1001 ) = __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error | |
| 1002 | |
| 1003 | |
| 1004 # remove remaining slots attributes, after the metaclass did the magic they | |
| 1005 # are unneeded and irritating as they contain wrong data for the subclasses. | |
| 1006 del ( | |
| 1007 Undefined.__slots__, | |
| 1008 ChainableUndefined.__slots__, | |
| 1009 DebugUndefined.__slots__, | |
| 1010 StrictUndefined.__slots__, | |
| 1011 ) |
