1# mako/runtime.py 2# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file> 3# 4# This module is part of Mako and is released under 5# the MIT License: http://www.opensource.org/licenses/mit-license.php 6 7"""provides runtime services for templates, including Context, 8Namespace, and various helper functions.""" 9 10import builtins 11import functools 12import sys 13 14from mako import compat 15from mako import exceptions 16from mako import util 17 18 19class Context: 20 21 """Provides runtime namespace, output buffer, and various 22 callstacks for templates. 23 24 See :ref:`runtime_toplevel` for detail on the usage of 25 :class:`.Context`. 26 27 """ 28 29 def __init__(self, buffer, **data): 30 self._buffer_stack = [buffer] 31 32 self._data = data 33 34 self._kwargs = data.copy() 35 self._with_template = None 36 self._outputting_as_unicode = None 37 self.namespaces = {} 38 39 # "capture" function which proxies to the 40 # generic "capture" function 41 self._data["capture"] = functools.partial(capture, self) 42 43 # "caller" stack used by def calls with content 44 self.caller_stack = self._data["caller"] = CallerStack() 45 46 def _set_with_template(self, t): 47 self._with_template = t 48 illegal_names = t.reserved_names.intersection(self._data) 49 if illegal_names: 50 raise exceptions.NameConflictError( 51 "Reserved words passed to render(): %s" 52 % ", ".join(illegal_names) 53 ) 54 55 @property 56 def lookup(self): 57 """Return the :class:`.TemplateLookup` associated 58 with this :class:`.Context`. 59 60 """ 61 return self._with_template.lookup 62 63 @property 64 def kwargs(self): 65 """Return the dictionary of top level keyword arguments associated 66 with this :class:`.Context`. 67 68 This dictionary only includes the top-level arguments passed to 69 :meth:`.Template.render`. It does not include names produced within 70 the template execution such as local variable names or special names 71 such as ``self``, ``next``, etc. 72 73 The purpose of this dictionary is primarily for the case that 74 a :class:`.Template` accepts arguments via its ``<%page>`` tag, 75 which are normally expected to be passed via :meth:`.Template.render`, 76 except the template is being called in an inheritance context, 77 using the ``body()`` method. :attr:`.Context.kwargs` can then be 78 used to propagate these arguments to the inheriting template:: 79 80 ${next.body(**context.kwargs)} 81 82 """ 83 return self._kwargs.copy() 84 85 def push_caller(self, caller): 86 """Push a ``caller`` callable onto the callstack for 87 this :class:`.Context`.""" 88 89 self.caller_stack.append(caller) 90 91 def pop_caller(self): 92 """Pop a ``caller`` callable onto the callstack for this 93 :class:`.Context`.""" 94 95 del self.caller_stack[-1] 96 97 def keys(self): 98 """Return a list of all names established in this :class:`.Context`.""" 99 100 return list(self._data.keys()) 101 102 def __getitem__(self, key): 103 if key in self._data: 104 return self._data[key] 105 else: 106 return builtins.__dict__[key] 107 108 def _push_writer(self): 109 """push a capturing buffer onto this Context and return 110 the new writer function.""" 111 112 buf = util.FastEncodingBuffer() 113 self._buffer_stack.append(buf) 114 return buf.write 115 116 def _pop_buffer_and_writer(self): 117 """pop the most recent capturing buffer from this Context 118 and return the current writer after the pop. 119 120 """ 121 122 buf = self._buffer_stack.pop() 123 return buf, self._buffer_stack[-1].write 124 125 def _push_buffer(self): 126 """push a capturing buffer onto this Context.""" 127 128 self._push_writer() 129 130 def _pop_buffer(self): 131 """pop the most recent capturing buffer from this Context.""" 132 133 return self._buffer_stack.pop() 134 135 def get(self, key, default=None): 136 """Return a value from this :class:`.Context`.""" 137 138 return self._data.get(key, builtins.__dict__.get(key, default)) 139 140 def write(self, string): 141 """Write a string to this :class:`.Context` object's 142 underlying output buffer.""" 143 144 self._buffer_stack[-1].write(string) 145 146 def writer(self): 147 """Return the current writer function.""" 148 149 return self._buffer_stack[-1].write 150 151 def _copy(self): 152 c = Context.__new__(Context) 153 c._buffer_stack = self._buffer_stack 154 c._data = self._data.copy() 155 c._kwargs = self._kwargs 156 c._with_template = self._with_template 157 c._outputting_as_unicode = self._outputting_as_unicode 158 c.namespaces = self.namespaces 159 c.caller_stack = self.caller_stack 160 return c 161 162 def _locals(self, d): 163 """Create a new :class:`.Context` with a copy of this 164 :class:`.Context`'s current state, 165 updated with the given dictionary. 166 167 The :attr:`.Context.kwargs` collection remains 168 unaffected. 169 170 171 """ 172 173 if not d: 174 return self 175 c = self._copy() 176 c._data.update(d) 177 return c 178 179 def _clean_inheritance_tokens(self): 180 """create a new copy of this :class:`.Context`. with 181 tokens related to inheritance state removed.""" 182 183 c = self._copy() 184 x = c._data 185 x.pop("self", None) 186 x.pop("parent", None) 187 x.pop("next", None) 188 return c 189 190 191class CallerStack(list): 192 def __init__(self): 193 self.nextcaller = None 194 195 def __nonzero__(self): 196 return self.__bool__() 197 198 def __bool__(self): 199 return len(self) and self._get_caller() and True or False 200 201 def _get_caller(self): 202 # this method can be removed once 203 # codegen MAGIC_NUMBER moves past 7 204 return self[-1] 205 206 def __getattr__(self, key): 207 return getattr(self._get_caller(), key) 208 209 def _push_frame(self): 210 frame = self.nextcaller or None 211 self.append(frame) 212 self.nextcaller = None 213 return frame 214 215 def _pop_frame(self): 216 self.nextcaller = self.pop() 217 218 219class Undefined: 220 221 """Represents an undefined value in a template. 222 223 All template modules have a constant value 224 ``UNDEFINED`` present which is an instance of this 225 object. 226 227 """ 228 229 def __str__(self): 230 raise NameError("Undefined") 231 232 def __nonzero__(self): 233 return self.__bool__() 234 235 def __bool__(self): 236 return False 237 238 239UNDEFINED = Undefined() 240STOP_RENDERING = "" 241 242 243class LoopStack: 244 245 """a stack for LoopContexts that implements the context manager protocol 246 to automatically pop off the top of the stack on context exit 247 """ 248 249 def __init__(self): 250 self.stack = [] 251 252 def _enter(self, iterable): 253 self._push(iterable) 254 return self._top 255 256 def _exit(self): 257 self._pop() 258 return self._top 259 260 @property 261 def _top(self): 262 if self.stack: 263 return self.stack[-1] 264 else: 265 return self 266 267 def _pop(self): 268 return self.stack.pop() 269 270 def _push(self, iterable): 271 new = LoopContext(iterable) 272 if self.stack: 273 new.parent = self.stack[-1] 274 return self.stack.append(new) 275 276 def __getattr__(self, key): 277 raise exceptions.RuntimeException("No loop context is established") 278 279 def __iter__(self): 280 return iter(self._top) 281 282 283class LoopContext: 284 285 """A magic loop variable. 286 Automatically accessible in any ``% for`` block. 287 288 See the section :ref:`loop_context` for usage 289 notes. 290 291 :attr:`parent` -> :class:`.LoopContext` or ``None`` 292 The parent loop, if one exists. 293 :attr:`index` -> `int` 294 The 0-based iteration count. 295 :attr:`reverse_index` -> `int` 296 The number of iterations remaining. 297 :attr:`first` -> `bool` 298 ``True`` on the first iteration, ``False`` otherwise. 299 :attr:`last` -> `bool` 300 ``True`` on the last iteration, ``False`` otherwise. 301 :attr:`even` -> `bool` 302 ``True`` when ``index`` is even. 303 :attr:`odd` -> `bool` 304 ``True`` when ``index`` is odd. 305 """ 306 307 def __init__(self, iterable): 308 self._iterable = iterable 309 self.index = 0 310 self.parent = None 311 312 def __iter__(self): 313 for i in self._iterable: 314 yield i 315 self.index += 1 316 317 @util.memoized_instancemethod 318 def __len__(self): 319 return len(self._iterable) 320 321 @property 322 def reverse_index(self): 323 return len(self) - self.index - 1 324 325 @property 326 def first(self): 327 return self.index == 0 328 329 @property 330 def last(self): 331 return self.index == len(self) - 1 332 333 @property 334 def even(self): 335 return not self.odd 336 337 @property 338 def odd(self): 339 return bool(self.index % 2) 340 341 def cycle(self, *values): 342 """Cycle through values as the loop progresses.""" 343 if not values: 344 raise ValueError("You must provide values to cycle through") 345 return values[self.index % len(values)] 346 347 348class _NSAttr: 349 def __init__(self, parent): 350 self.__parent = parent 351 352 def __getattr__(self, key): 353 ns = self.__parent 354 while ns: 355 if hasattr(ns.module, key): 356 return getattr(ns.module, key) 357 else: 358 ns = ns.inherits 359 raise AttributeError(key) 360 361 362class Namespace: 363 364 """Provides access to collections of rendering methods, which 365 can be local, from other templates, or from imported modules. 366 367 To access a particular rendering method referenced by a 368 :class:`.Namespace`, use plain attribute access: 369 370 .. sourcecode:: mako 371 372 ${some_namespace.foo(x, y, z)} 373 374 :class:`.Namespace` also contains several built-in attributes 375 described here. 376 377 """ 378 379 def __init__( 380 self, 381 name, 382 context, 383 callables=None, 384 inherits=None, 385 populate_self=True, 386 calling_uri=None, 387 ): 388 self.name = name 389 self.context = context 390 self.inherits = inherits 391 if callables is not None: 392 self.callables = {c.__name__: c for c in callables} 393 394 callables = () 395 396 module = None 397 """The Python module referenced by this :class:`.Namespace`. 398 399 If the namespace references a :class:`.Template`, then 400 this module is the equivalent of ``template.module``, 401 i.e. the generated module for the template. 402 403 """ 404 405 template = None 406 """The :class:`.Template` object referenced by this 407 :class:`.Namespace`, if any. 408 409 """ 410 411 context = None 412 """The :class:`.Context` object for this :class:`.Namespace`. 413 414 Namespaces are often created with copies of contexts that 415 contain slightly different data, particularly in inheritance 416 scenarios. Using the :class:`.Context` off of a :class:`.Namespace` one 417 can traverse an entire chain of templates that inherit from 418 one-another. 419 420 """ 421 422 filename = None 423 """The path of the filesystem file used for this 424 :class:`.Namespace`'s module or template. 425 426 If this is a pure module-based 427 :class:`.Namespace`, this evaluates to ``module.__file__``. If a 428 template-based namespace, it evaluates to the original 429 template file location. 430 431 """ 432 433 uri = None 434 """The URI for this :class:`.Namespace`'s template. 435 436 I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`. 437 438 This is the equivalent of :attr:`.Template.uri`. 439 440 """ 441 442 _templateuri = None 443 444 @util.memoized_property 445 def attr(self): 446 """Access module level attributes by name. 447 448 This accessor allows templates to supply "scalar" 449 attributes which are particularly handy in inheritance 450 relationships. 451 452 .. seealso:: 453 454 :ref:`inheritance_attr` 455 456 :ref:`namespace_attr_for_includes` 457 458 """ 459 return _NSAttr(self) 460 461 def get_namespace(self, uri): 462 """Return a :class:`.Namespace` corresponding to the given ``uri``. 463 464 If the given ``uri`` is a relative URI (i.e. it does not 465 contain a leading slash ``/``), the ``uri`` is adjusted to 466 be relative to the ``uri`` of the namespace itself. This 467 method is therefore mostly useful off of the built-in 468 ``local`` namespace, described in :ref:`namespace_local`. 469 470 In 471 most cases, a template wouldn't need this function, and 472 should instead use the ``<%namespace>`` tag to load 473 namespaces. However, since all ``<%namespace>`` tags are 474 evaluated before the body of a template ever runs, 475 this method can be used to locate namespaces using 476 expressions that were generated within the body code of 477 the template, or to conditionally use a particular 478 namespace. 479 480 """ 481 key = (self, uri) 482 if key in self.context.namespaces: 483 return self.context.namespaces[key] 484 ns = TemplateNamespace( 485 uri, 486 self.context._copy(), 487 templateuri=uri, 488 calling_uri=self._templateuri, 489 ) 490 self.context.namespaces[key] = ns 491 return ns 492 493 def get_template(self, uri): 494 """Return a :class:`.Template` from the given ``uri``. 495 496 The ``uri`` resolution is relative to the ``uri`` of this 497 :class:`.Namespace` object's :class:`.Template`. 498 499 """ 500 return _lookup_template(self.context, uri, self._templateuri) 501 502 def get_cached(self, key, **kwargs): 503 """Return a value from the :class:`.Cache` referenced by this 504 :class:`.Namespace` object's :class:`.Template`. 505 506 The advantage to this method versus direct access to the 507 :class:`.Cache` is that the configuration parameters 508 declared in ``<%page>`` take effect here, thereby calling 509 up the same configured backend as that configured 510 by ``<%page>``. 511 512 """ 513 514 return self.cache.get(key, **kwargs) 515 516 @property 517 def cache(self): 518 """Return the :class:`.Cache` object referenced 519 by this :class:`.Namespace` object's 520 :class:`.Template`. 521 522 """ 523 return self.template.cache 524 525 def include_file(self, uri, **kwargs): 526 """Include a file at the given ``uri``.""" 527 528 _include_file(self.context, uri, self._templateuri, **kwargs) 529 530 def _populate(self, d, l): 531 for ident in l: 532 if ident == "*": 533 for k, v in self._get_star(): 534 d[k] = v 535 else: 536 d[ident] = getattr(self, ident) 537 538 def _get_star(self): 539 if self.callables: 540 for key in self.callables: 541 yield (key, self.callables[key]) 542 543 def __getattr__(self, key): 544 if key in self.callables: 545 val = self.callables[key] 546 elif self.inherits: 547 val = getattr(self.inherits, key) 548 else: 549 raise AttributeError( 550 "Namespace '%s' has no member '%s'" % (self.name, key) 551 ) 552 setattr(self, key, val) 553 return val 554 555 556class TemplateNamespace(Namespace): 557 558 """A :class:`.Namespace` specific to a :class:`.Template` instance.""" 559 560 def __init__( 561 self, 562 name, 563 context, 564 template=None, 565 templateuri=None, 566 callables=None, 567 inherits=None, 568 populate_self=True, 569 calling_uri=None, 570 ): 571 self.name = name 572 self.context = context 573 self.inherits = inherits 574 if callables is not None: 575 self.callables = {c.__name__: c for c in callables} 576 577 if templateuri is not None: 578 self.template = _lookup_template(context, templateuri, calling_uri) 579 self._templateuri = self.template.module._template_uri 580 elif template is not None: 581 self.template = template 582 self._templateuri = template.module._template_uri 583 else: 584 raise TypeError("'template' argument is required.") 585 586 if populate_self: 587 lclcallable, lclcontext = _populate_self_namespace( 588 context, self.template, self_ns=self 589 ) 590 591 @property 592 def module(self): 593 """The Python module referenced by this :class:`.Namespace`. 594 595 If the namespace references a :class:`.Template`, then 596 this module is the equivalent of ``template.module``, 597 i.e. the generated module for the template. 598 599 """ 600 return self.template.module 601 602 @property 603 def filename(self): 604 """The path of the filesystem file used for this 605 :class:`.Namespace`'s module or template. 606 """ 607 return self.template.filename 608 609 @property 610 def uri(self): 611 """The URI for this :class:`.Namespace`'s template. 612 613 I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`. 614 615 This is the equivalent of :attr:`.Template.uri`. 616 617 """ 618 return self.template.uri 619 620 def _get_star(self): 621 if self.callables: 622 for key in self.callables: 623 yield (key, self.callables[key]) 624 625 def get(key): 626 callable_ = self.template._get_def_callable(key) 627 return functools.partial(callable_, self.context) 628 629 for k in self.template.module._exports: 630 yield (k, get(k)) 631 632 def __getattr__(self, key): 633 if key in self.callables: 634 val = self.callables[key] 635 elif self.template.has_def(key): 636 callable_ = self.template._get_def_callable(key) 637 val = functools.partial(callable_, self.context) 638 elif self.inherits: 639 val = getattr(self.inherits, key) 640 641 else: 642 raise AttributeError( 643 "Namespace '%s' has no member '%s'" % (self.name, key) 644 ) 645 setattr(self, key, val) 646 return val 647 648 649class ModuleNamespace(Namespace): 650 651 """A :class:`.Namespace` specific to a Python module instance.""" 652 653 def __init__( 654 self, 655 name, 656 context, 657 module, 658 callables=None, 659 inherits=None, 660 populate_self=True, 661 calling_uri=None, 662 ): 663 self.name = name 664 self.context = context 665 self.inherits = inherits 666 if callables is not None: 667 self.callables = {c.__name__: c for c in callables} 668 669 mod = __import__(module) 670 for token in module.split(".")[1:]: 671 mod = getattr(mod, token) 672 self.module = mod 673 674 @property 675 def filename(self): 676 """The path of the filesystem file used for this 677 :class:`.Namespace`'s module or template. 678 """ 679 return self.module.__file__ 680 681 def _get_star(self): 682 if self.callables: 683 for key in self.callables: 684 yield (key, self.callables[key]) 685 for key in dir(self.module): 686 if key[0] != "_": 687 callable_ = getattr(self.module, key) 688 if callable(callable_): 689 yield key, functools.partial(callable_, self.context) 690 691 def __getattr__(self, key): 692 if key in self.callables: 693 val = self.callables[key] 694 elif hasattr(self.module, key): 695 callable_ = getattr(self.module, key) 696 val = functools.partial(callable_, self.context) 697 elif self.inherits: 698 val = getattr(self.inherits, key) 699 else: 700 raise AttributeError( 701 "Namespace '%s' has no member '%s'" % (self.name, key) 702 ) 703 setattr(self, key, val) 704 return val 705 706 707def supports_caller(func): 708 """Apply a caller_stack compatibility decorator to a plain 709 Python function. 710 711 See the example in :ref:`namespaces_python_modules`. 712 713 """ 714 715 def wrap_stackframe(context, *args, **kwargs): 716 context.caller_stack._push_frame() 717 try: 718 return func(context, *args, **kwargs) 719 finally: 720 context.caller_stack._pop_frame() 721 722 return wrap_stackframe 723 724 725def capture(context, callable_, *args, **kwargs): 726 """Execute the given template def, capturing the output into 727 a buffer. 728 729 See the example in :ref:`namespaces_python_modules`. 730 731 """ 732 733 if not callable(callable_): 734 raise exceptions.RuntimeException( 735 "capture() function expects a callable as " 736 "its argument (i.e. capture(func, *args, **kwargs))" 737 ) 738 context._push_buffer() 739 try: 740 callable_(*args, **kwargs) 741 finally: 742 buf = context._pop_buffer() 743 return buf.getvalue() 744 745 746def _decorate_toplevel(fn): 747 def decorate_render(render_fn): 748 def go(context, *args, **kw): 749 def y(*args, **kw): 750 return render_fn(context, *args, **kw) 751 752 try: 753 y.__name__ = render_fn.__name__[7:] 754 except TypeError: 755 # < Python 2.4 756 pass 757 return fn(y)(context, *args, **kw) 758 759 return go 760 761 return decorate_render 762 763 764def _decorate_inline(context, fn): 765 def decorate_render(render_fn): 766 dec = fn(render_fn) 767 768 def go(*args, **kw): 769 return dec(context, *args, **kw) 770 771 return go 772 773 return decorate_render 774 775 776def _include_file(context, uri, calling_uri, **kwargs): 777 """locate the template from the given uri and include it in 778 the current output.""" 779 780 template = _lookup_template(context, uri, calling_uri) 781 (callable_, ctx) = _populate_self_namespace( 782 context._clean_inheritance_tokens(), template 783 ) 784 kwargs = _kwargs_for_include(callable_, context._data, **kwargs) 785 if template.include_error_handler: 786 try: 787 callable_(ctx, **kwargs) 788 except Exception: 789 result = template.include_error_handler(ctx, compat.exception_as()) 790 if not result: 791 raise 792 else: 793 callable_(ctx, **kwargs) 794 795 796def _inherit_from(context, uri, calling_uri): 797 """called by the _inherit method in template modules to set 798 up the inheritance chain at the start of a template's 799 execution.""" 800 801 if uri is None: 802 return None 803 template = _lookup_template(context, uri, calling_uri) 804 self_ns = context["self"] 805 ih = self_ns 806 while ih.inherits is not None: 807 ih = ih.inherits 808 lclcontext = context._locals({"next": ih}) 809 ih.inherits = TemplateNamespace( 810 "self:%s" % template.uri, 811 lclcontext, 812 template=template, 813 populate_self=False, 814 ) 815 context._data["parent"] = lclcontext._data["local"] = ih.inherits 816 callable_ = getattr(template.module, "_mako_inherit", None) 817 if callable_ is not None: 818 ret = callable_(template, lclcontext) 819 if ret: 820 return ret 821 822 gen_ns = getattr(template.module, "_mako_generate_namespaces", None) 823 if gen_ns is not None: 824 gen_ns(context) 825 return (template.callable_, lclcontext) 826 827 828def _lookup_template(context, uri, relativeto): 829 lookup = context._with_template.lookup 830 if lookup is None: 831 raise exceptions.TemplateLookupException( 832 "Template '%s' has no TemplateLookup associated" 833 % context._with_template.uri 834 ) 835 uri = lookup.adjust_uri(uri, relativeto) 836 try: 837 return lookup.get_template(uri) 838 except exceptions.TopLevelLookupException as e: 839 raise exceptions.TemplateLookupException( 840 str(compat.exception_as()) 841 ) from e 842 843 844def _populate_self_namespace(context, template, self_ns=None): 845 if self_ns is None: 846 self_ns = TemplateNamespace( 847 "self:%s" % template.uri, 848 context, 849 template=template, 850 populate_self=False, 851 ) 852 context._data["self"] = context._data["local"] = self_ns 853 if hasattr(template.module, "_mako_inherit"): 854 ret = template.module._mako_inherit(template, context) 855 if ret: 856 return ret 857 return (template.callable_, context) 858 859 860def _render(template, callable_, args, data, as_unicode=False): 861 """create a Context and return the string 862 output of the given template and template callable.""" 863 864 if as_unicode: 865 buf = util.FastEncodingBuffer() 866 else: 867 buf = util.FastEncodingBuffer( 868 encoding=template.output_encoding, errors=template.encoding_errors 869 ) 870 context = Context(buf, **data) 871 context._outputting_as_unicode = as_unicode 872 context._set_with_template(template) 873 874 _render_context( 875 template, 876 callable_, 877 context, 878 *args, 879 **_kwargs_for_callable(callable_, data), 880 ) 881 return context._pop_buffer().getvalue() 882 883 884def _kwargs_for_callable(callable_, data): 885 argspec = compat.inspect_getargspec(callable_) 886 # for normal pages, **pageargs is usually present 887 if argspec[2]: 888 return data 889 890 # for rendering defs from the top level, figure out the args 891 namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None] 892 kwargs = {} 893 for arg in namedargs: 894 if arg != "context" and arg in data and arg not in kwargs: 895 kwargs[arg] = data[arg] 896 return kwargs 897 898 899def _kwargs_for_include(callable_, data, **kwargs): 900 argspec = compat.inspect_getargspec(callable_) 901 namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None] 902 for arg in namedargs: 903 if arg != "context" and arg in data and arg not in kwargs: 904 kwargs[arg] = data[arg] 905 return kwargs 906 907 908def _render_context(tmpl, callable_, context, *args, **kwargs): 909 import mako.template as template 910 911 # create polymorphic 'self' namespace for this 912 # template with possibly updated context 913 if not isinstance(tmpl, template.DefTemplate): 914 # if main render method, call from the base of the inheritance stack 915 (inherit, lclcontext) = _populate_self_namespace(context, tmpl) 916 _exec_template(inherit, lclcontext, args=args, kwargs=kwargs) 917 else: 918 # otherwise, call the actual rendering method specified 919 (inherit, lclcontext) = _populate_self_namespace(context, tmpl.parent) 920 _exec_template(callable_, context, args=args, kwargs=kwargs) 921 922 923def _exec_template(callable_, context, args=None, kwargs=None): 924 """execute a rendering callable given the callable, a 925 Context, and optional explicit arguments 926 927 the contextual Template will be located if it exists, and 928 the error handling options specified on that Template will 929 be interpreted here. 930 """ 931 template = context._with_template 932 if template is not None and ( 933 template.format_exceptions or template.error_handler 934 ): 935 try: 936 callable_(context, *args, **kwargs) 937 except Exception: 938 _render_error(template, context, compat.exception_as()) 939 except: 940 e = sys.exc_info()[0] 941 _render_error(template, context, e) 942 else: 943 callable_(context, *args, **kwargs) 944 945 946def _render_error(template, context, error): 947 if template.error_handler: 948 result = template.error_handler(context, error) 949 if not result: 950 tp, value, tb = sys.exc_info() 951 if value and tb: 952 raise value.with_traceback(tb) 953 else: 954 raise error 955 else: 956 error_template = exceptions.html_error_template() 957 if context._outputting_as_unicode: 958 context._buffer_stack[:] = [util.FastEncodingBuffer()] 959 else: 960 context._buffer_stack[:] = [ 961 util.FastEncodingBuffer( 962 error_template.output_encoding, 963 error_template.encoding_errors, 964 ) 965 ] 966 967 context._set_with_template(error_template) 968 error_template.render_context(context, error=error) 969