Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/mako/runtime.py: 28%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

449 statements  

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 """Provides runtime namespace, output buffer, and various 

21 callstacks for templates. 

22 

23 See :ref:`runtime_toplevel` for detail on the usage of 

24 :class:`.Context`. 

25 

26 """ 

27 

28 def __init__(self, buffer, **data): 

29 self._buffer_stack = [buffer] 

30 

31 self._data = data 

32 

33 self._kwargs = data.copy() 

34 self._with_template = None 

35 self._outputting_as_unicode = None 

36 self.namespaces = {} 

37 

38 # "capture" function which proxies to the 

39 # generic "capture" function 

40 self._data["capture"] = functools.partial(capture, self) 

41 

42 # "caller" stack used by def calls with content 

43 self.caller_stack = self._data["caller"] = CallerStack() 

44 

45 def _set_with_template(self, t): 

46 self._with_template = t 

47 illegal_names = t.reserved_names.intersection(self._data) 

48 if illegal_names: 

49 raise exceptions.NameConflictError( 

50 "Reserved words passed to render(): %s" 

51 % ", ".join(illegal_names) 

52 ) 

53 

54 @property 

55 def lookup(self): 

56 """Return the :class:`.TemplateLookup` associated 

57 with this :class:`.Context`. 

58 

59 """ 

60 return self._with_template.lookup 

61 

62 @property 

63 def kwargs(self): 

64 """Return the dictionary of top level keyword arguments associated 

65 with this :class:`.Context`. 

66 

67 This dictionary only includes the top-level arguments passed to 

68 :meth:`.Template.render`. It does not include names produced within 

69 the template execution such as local variable names or special names 

70 such as ``self``, ``next``, etc. 

71 

72 The purpose of this dictionary is primarily for the case that 

73 a :class:`.Template` accepts arguments via its ``<%page>`` tag, 

74 which are normally expected to be passed via :meth:`.Template.render`, 

75 except the template is being called in an inheritance context, 

76 using the ``body()`` method. :attr:`.Context.kwargs` can then be 

77 used to propagate these arguments to the inheriting template:: 

78 

79 ${next.body(**context.kwargs)} 

80 

81 """ 

82 return self._kwargs.copy() 

83 

84 def push_caller(self, caller): 

85 """Push a ``caller`` callable onto the callstack for 

86 this :class:`.Context`.""" 

87 

88 self.caller_stack.append(caller) 

89 

90 def pop_caller(self): 

91 """Pop a ``caller`` callable onto the callstack for this 

92 :class:`.Context`.""" 

93 

94 del self.caller_stack[-1] 

95 

96 def keys(self): 

97 """Return a list of all names established in this :class:`.Context`.""" 

98 

99 return list(self._data.keys()) 

100 

101 def __getitem__(self, key): 

102 if key in self._data: 

103 return self._data[key] 

104 else: 

105 return builtins.__dict__[key] 

106 

107 def _push_writer(self): 

108 """push a capturing buffer onto this Context and return 

109 the new writer function.""" 

110 

111 buf = util.FastEncodingBuffer() 

112 self._buffer_stack.append(buf) 

113 return buf.write 

114 

115 def _pop_buffer_and_writer(self): 

116 """pop the most recent capturing buffer from this Context 

117 and return the current writer after the pop. 

118 

119 """ 

120 

121 buf = self._buffer_stack.pop() 

122 return buf, self._buffer_stack[-1].write 

123 

124 def _push_buffer(self): 

125 """push a capturing buffer onto this Context.""" 

126 

127 self._push_writer() 

128 

129 def _pop_buffer(self): 

130 """pop the most recent capturing buffer from this Context.""" 

131 

132 return self._buffer_stack.pop() 

133 

134 def get(self, key, default=None): 

135 """Return a value from this :class:`.Context`.""" 

136 

137 return self._data.get(key, builtins.__dict__.get(key, default)) 

138 

139 def write(self, string): 

140 """Write a string to this :class:`.Context` object's 

141 underlying output buffer.""" 

142 

143 self._buffer_stack[-1].write(string) 

144 

145 def writer(self): 

146 """Return the current writer function.""" 

147 

148 return self._buffer_stack[-1].write 

149 

150 def _copy(self): 

151 c = Context.__new__(Context) 

152 c._buffer_stack = self._buffer_stack 

153 c._data = self._data.copy() 

154 c._kwargs = self._kwargs 

155 c._with_template = self._with_template 

156 c._outputting_as_unicode = self._outputting_as_unicode 

157 c.namespaces = self.namespaces 

158 c.caller_stack = self.caller_stack 

159 return c 

160 

161 def _locals(self, d): 

162 """Create a new :class:`.Context` with a copy of this 

163 :class:`.Context`'s current state, 

164 updated with the given dictionary. 

165 

166 The :attr:`.Context.kwargs` collection remains 

167 unaffected. 

168 

169 

170 """ 

171 

172 if not d: 

173 return self 

174 c = self._copy() 

175 c._data.update(d) 

176 return c 

177 

178 def _clean_inheritance_tokens(self): 

179 """create a new copy of this :class:`.Context`. with 

180 tokens related to inheritance state removed.""" 

181 

182 c = self._copy() 

183 x = c._data 

184 x.pop("self", None) 

185 x.pop("parent", None) 

186 x.pop("next", None) 

187 return c 

188 

189 

190class CallerStack(list): 

191 def __init__(self): 

192 self.nextcaller = None 

193 

194 def __nonzero__(self): 

195 return self.__bool__() 

196 

197 def __bool__(self): 

198 return len(self) and self._get_caller() and True or False 

199 

200 def _get_caller(self): 

201 # this method can be removed once 

202 # codegen MAGIC_NUMBER moves past 7 

203 return self[-1] 

204 

205 def __getattr__(self, key): 

206 return getattr(self._get_caller(), key) 

207 

208 def _push_frame(self): 

209 frame = self.nextcaller or None 

210 self.append(frame) 

211 self.nextcaller = None 

212 return frame 

213 

214 def _pop_frame(self): 

215 self.nextcaller = self.pop() 

216 

217 

218class Undefined: 

219 """Represents an undefined value in a template. 

220 

221 All template modules have a constant value 

222 ``UNDEFINED`` present which is an instance of this 

223 object. 

224 

225 """ 

226 

227 def __str__(self): 

228 raise NameError("Undefined") 

229 

230 def __nonzero__(self): 

231 return self.__bool__() 

232 

233 def __bool__(self): 

234 return False 

235 

236 

237UNDEFINED = Undefined() 

238STOP_RENDERING = "" 

239 

240 

241class LoopStack: 

242 """a stack for LoopContexts that implements the context manager protocol 

243 to automatically pop off the top of the stack on context exit 

244 """ 

245 

246 def __init__(self): 

247 self.stack = [] 

248 

249 def _enter(self, iterable): 

250 self._push(iterable) 

251 return self._top 

252 

253 def _exit(self): 

254 self._pop() 

255 return self._top 

256 

257 @property 

258 def _top(self): 

259 if self.stack: 

260 return self.stack[-1] 

261 else: 

262 return self 

263 

264 def _pop(self): 

265 return self.stack.pop() 

266 

267 def _push(self, iterable): 

268 new = LoopContext(iterable) 

269 if self.stack: 

270 new.parent = self.stack[-1] 

271 return self.stack.append(new) 

272 

273 def __getattr__(self, key): 

274 raise exceptions.RuntimeException("No loop context is established") 

275 

276 def __iter__(self): 

277 return iter(self._top) 

278 

279 

280class LoopContext: 

281 """A magic loop variable. 

282 Automatically accessible in any ``% for`` block. 

283 

284 See the section :ref:`loop_context` for usage 

285 notes. 

286 

287 :attr:`parent` -> :class:`.LoopContext` or ``None`` 

288 The parent loop, if one exists. 

289 :attr:`index` -> `int` 

290 The 0-based iteration count. 

291 :attr:`reverse_index` -> `int` 

292 The number of iterations remaining. 

293 :attr:`first` -> `bool` 

294 ``True`` on the first iteration, ``False`` otherwise. 

295 :attr:`last` -> `bool` 

296 ``True`` on the last iteration, ``False`` otherwise. 

297 :attr:`even` -> `bool` 

298 ``True`` when ``index`` is even. 

299 :attr:`odd` -> `bool` 

300 ``True`` when ``index`` is odd. 

301 """ 

302 

303 def __init__(self, iterable): 

304 self._iterable = iterable 

305 self.index = 0 

306 self.parent = None 

307 

308 def __iter__(self): 

309 for i in self._iterable: 

310 yield i 

311 self.index += 1 

312 

313 @util.memoized_instancemethod 

314 def __len__(self): 

315 return len(self._iterable) 

316 

317 @property 

318 def reverse_index(self): 

319 return len(self) - self.index - 1 

320 

321 @property 

322 def first(self): 

323 return self.index == 0 

324 

325 @property 

326 def last(self): 

327 return self.index == len(self) - 1 

328 

329 @property 

330 def even(self): 

331 return not self.odd 

332 

333 @property 

334 def odd(self): 

335 return bool(self.index % 2) 

336 

337 def cycle(self, *values): 

338 """Cycle through values as the loop progresses.""" 

339 if not values: 

340 raise ValueError("You must provide values to cycle through") 

341 return values[self.index % len(values)] 

342 

343 

344class _NSAttr: 

345 def __init__(self, parent): 

346 self.__parent = parent 

347 

348 def __getattr__(self, key): 

349 ns = self.__parent 

350 while ns: 

351 if hasattr(ns.module, key): 

352 return getattr(ns.module, key) 

353 else: 

354 ns = ns.inherits 

355 raise AttributeError(key) 

356 

357 

358class Namespace: 

359 """Provides access to collections of rendering methods, which 

360 can be local, from other templates, or from imported modules. 

361 

362 To access a particular rendering method referenced by a 

363 :class:`.Namespace`, use plain attribute access: 

364 

365 .. sourcecode:: mako 

366 

367 ${some_namespace.foo(x, y, z)} 

368 

369 :class:`.Namespace` also contains several built-in attributes 

370 described here. 

371 

372 """ 

373 

374 def __init__( 

375 self, 

376 name, 

377 context, 

378 callables=None, 

379 inherits=None, 

380 populate_self=True, 

381 calling_uri=None, 

382 ): 

383 self.name = name 

384 self.context = context 

385 self.inherits = inherits 

386 if callables is not None: 

387 self.callables = {c.__name__: c for c in callables} 

388 

389 callables = () 

390 

391 module = None 

392 """The Python module referenced by this :class:`.Namespace`. 

393 

394 If the namespace references a :class:`.Template`, then 

395 this module is the equivalent of ``template.module``, 

396 i.e. the generated module for the template. 

397 

398 """ 

399 

400 template = None 

401 """The :class:`.Template` object referenced by this 

402 :class:`.Namespace`, if any. 

403 

404 """ 

405 

406 context = None 

407 """The :class:`.Context` object for this :class:`.Namespace`. 

408 

409 Namespaces are often created with copies of contexts that 

410 contain slightly different data, particularly in inheritance 

411 scenarios. Using the :class:`.Context` off of a :class:`.Namespace` one 

412 can traverse an entire chain of templates that inherit from 

413 one-another. 

414 

415 """ 

416 

417 filename = None 

418 """The path of the filesystem file used for this 

419 :class:`.Namespace`'s module or template. 

420 

421 If this is a pure module-based 

422 :class:`.Namespace`, this evaluates to ``module.__file__``. If a 

423 template-based namespace, it evaluates to the original 

424 template file location. 

425 

426 """ 

427 

428 uri = None 

429 """The URI for this :class:`.Namespace`'s template. 

430 

431 I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`. 

432 

433 This is the equivalent of :attr:`.Template.uri`. 

434 

435 """ 

436 

437 _templateuri = None 

438 

439 @util.memoized_property 

440 def attr(self): 

441 """Access module level attributes by name. 

442 

443 This accessor allows templates to supply "scalar" 

444 attributes which are particularly handy in inheritance 

445 relationships. 

446 

447 .. seealso:: 

448 

449 :ref:`inheritance_attr` 

450 

451 :ref:`namespace_attr_for_includes` 

452 

453 """ 

454 return _NSAttr(self) 

455 

456 def get_namespace(self, uri): 

457 """Return a :class:`.Namespace` corresponding to the given ``uri``. 

458 

459 If the given ``uri`` is a relative URI (i.e. it does not 

460 contain a leading slash ``/``), the ``uri`` is adjusted to 

461 be relative to the ``uri`` of the namespace itself. This 

462 method is therefore mostly useful off of the built-in 

463 ``local`` namespace, described in :ref:`namespace_local`. 

464 

465 In 

466 most cases, a template wouldn't need this function, and 

467 should instead use the ``<%namespace>`` tag to load 

468 namespaces. However, since all ``<%namespace>`` tags are 

469 evaluated before the body of a template ever runs, 

470 this method can be used to locate namespaces using 

471 expressions that were generated within the body code of 

472 the template, or to conditionally use a particular 

473 namespace. 

474 

475 """ 

476 key = (self, uri) 

477 if key in self.context.namespaces: 

478 return self.context.namespaces[key] 

479 ns = TemplateNamespace( 

480 uri, 

481 self.context._copy(), 

482 templateuri=uri, 

483 calling_uri=self._templateuri, 

484 ) 

485 self.context.namespaces[key] = ns 

486 return ns 

487 

488 def get_template(self, uri): 

489 """Return a :class:`.Template` from the given ``uri``. 

490 

491 The ``uri`` resolution is relative to the ``uri`` of this 

492 :class:`.Namespace` object's :class:`.Template`. 

493 

494 """ 

495 return _lookup_template(self.context, uri, self._templateuri) 

496 

497 def get_cached(self, key, **kwargs): 

498 """Return a value from the :class:`.Cache` referenced by this 

499 :class:`.Namespace` object's :class:`.Template`. 

500 

501 The advantage to this method versus direct access to the 

502 :class:`.Cache` is that the configuration parameters 

503 declared in ``<%page>`` take effect here, thereby calling 

504 up the same configured backend as that configured 

505 by ``<%page>``. 

506 

507 """ 

508 

509 return self.cache.get(key, **kwargs) 

510 

511 @property 

512 def cache(self): 

513 """Return the :class:`.Cache` object referenced 

514 by this :class:`.Namespace` object's 

515 :class:`.Template`. 

516 

517 """ 

518 return self.template.cache 

519 

520 def include_file(self, uri, **kwargs): 

521 """Include a file at the given ``uri``.""" 

522 

523 _include_file(self.context, uri, self._templateuri, **kwargs) 

524 

525 def _populate(self, d, l): 

526 for ident in l: 

527 if ident == "*": 

528 for k, v in self._get_star(): 

529 d[k] = v 

530 else: 

531 d[ident] = getattr(self, ident) 

532 

533 def _get_star(self): 

534 if self.callables: 

535 for key in self.callables: 

536 yield (key, self.callables[key]) 

537 

538 def __getattr__(self, key): 

539 if key in self.callables: 

540 val = self.callables[key] 

541 elif self.inherits: 

542 val = getattr(self.inherits, key) 

543 else: 

544 raise AttributeError( 

545 "Namespace '%s' has no member '%s'" % (self.name, key) 

546 ) 

547 setattr(self, key, val) 

548 return val 

549 

550 

551class TemplateNamespace(Namespace): 

552 """A :class:`.Namespace` specific to a :class:`.Template` instance.""" 

553 

554 def __init__( 

555 self, 

556 name, 

557 context, 

558 template=None, 

559 templateuri=None, 

560 callables=None, 

561 inherits=None, 

562 populate_self=True, 

563 calling_uri=None, 

564 ): 

565 self.name = name 

566 self.context = context 

567 self.inherits = inherits 

568 if callables is not None: 

569 self.callables = {c.__name__: c for c in callables} 

570 

571 if templateuri is not None: 

572 self.template = _lookup_template(context, templateuri, calling_uri) 

573 self._templateuri = self.template.module._template_uri 

574 elif template is not None: 

575 self.template = template 

576 self._templateuri = template.module._template_uri 

577 else: 

578 raise TypeError("'template' argument is required.") 

579 

580 if populate_self: 

581 lclcallable, lclcontext = _populate_self_namespace( 

582 context, self.template, self_ns=self 

583 ) 

584 

585 @property 

586 def module(self): 

587 """The Python module referenced by this :class:`.Namespace`. 

588 

589 If the namespace references a :class:`.Template`, then 

590 this module is the equivalent of ``template.module``, 

591 i.e. the generated module for the template. 

592 

593 """ 

594 return self.template.module 

595 

596 @property 

597 def filename(self): 

598 """The path of the filesystem file used for this 

599 :class:`.Namespace`'s module or template. 

600 """ 

601 return self.template.filename 

602 

603 @property 

604 def uri(self): 

605 """The URI for this :class:`.Namespace`'s template. 

606 

607 I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`. 

608 

609 This is the equivalent of :attr:`.Template.uri`. 

610 

611 """ 

612 return self.template.uri 

613 

614 def _get_star(self): 

615 if self.callables: 

616 for key in self.callables: 

617 yield (key, self.callables[key]) 

618 

619 def get(key): 

620 callable_ = self.template._get_def_callable(key) 

621 return functools.partial(callable_, self.context) 

622 

623 for k in self.template.module._exports: 

624 yield (k, get(k)) 

625 

626 def __getattr__(self, key): 

627 if key in self.callables: 

628 val = self.callables[key] 

629 elif self.template.has_def(key): 

630 callable_ = self.template._get_def_callable(key) 

631 val = functools.partial(callable_, self.context) 

632 elif self.inherits: 

633 val = getattr(self.inherits, key) 

634 

635 else: 

636 raise AttributeError( 

637 "Namespace '%s' has no member '%s'" % (self.name, key) 

638 ) 

639 setattr(self, key, val) 

640 return val 

641 

642 

643class ModuleNamespace(Namespace): 

644 """A :class:`.Namespace` specific to a Python module instance.""" 

645 

646 def __init__( 

647 self, 

648 name, 

649 context, 

650 module, 

651 callables=None, 

652 inherits=None, 

653 populate_self=True, 

654 calling_uri=None, 

655 ): 

656 self.name = name 

657 self.context = context 

658 self.inherits = inherits 

659 if callables is not None: 

660 self.callables = {c.__name__: c for c in callables} 

661 

662 mod = __import__(module) 

663 for token in module.split(".")[1:]: 

664 mod = getattr(mod, token) 

665 self.module = mod 

666 

667 @property 

668 def filename(self): 

669 """The path of the filesystem file used for this 

670 :class:`.Namespace`'s module or template. 

671 """ 

672 return self.module.__file__ 

673 

674 def _get_star(self): 

675 if self.callables: 

676 for key in self.callables: 

677 yield (key, self.callables[key]) 

678 for key in dir(self.module): 

679 if key[0] != "_": 

680 callable_ = getattr(self.module, key) 

681 if callable(callable_): 

682 yield key, functools.partial(callable_, self.context) 

683 

684 def __getattr__(self, key): 

685 if key in self.callables: 

686 val = self.callables[key] 

687 elif hasattr(self.module, key): 

688 callable_ = getattr(self.module, key) 

689 val = functools.partial(callable_, self.context) 

690 elif self.inherits: 

691 val = getattr(self.inherits, key) 

692 else: 

693 raise AttributeError( 

694 "Namespace '%s' has no member '%s'" % (self.name, key) 

695 ) 

696 setattr(self, key, val) 

697 return val 

698 

699 

700def supports_caller(func): 

701 """Apply a caller_stack compatibility decorator to a plain 

702 Python function. 

703 

704 See the example in :ref:`namespaces_python_modules`. 

705 

706 """ 

707 

708 def wrap_stackframe(context, *args, **kwargs): 

709 context.caller_stack._push_frame() 

710 try: 

711 return func(context, *args, **kwargs) 

712 finally: 

713 context.caller_stack._pop_frame() 

714 

715 return wrap_stackframe 

716 

717 

718def capture(context, callable_, *args, **kwargs): 

719 """Execute the given template def, capturing the output into 

720 a buffer. 

721 

722 See the example in :ref:`namespaces_python_modules`. 

723 

724 """ 

725 

726 if not callable(callable_): 

727 raise exceptions.RuntimeException( 

728 "capture() function expects a callable as " 

729 "its argument (i.e. capture(func, *args, **kwargs))" 

730 ) 

731 context._push_buffer() 

732 try: 

733 callable_(*args, **kwargs) 

734 finally: 

735 buf = context._pop_buffer() 

736 return buf.getvalue() 

737 

738 

739def _decorate_toplevel(fn): 

740 def decorate_render(render_fn): 

741 def go(context, *args, **kw): 

742 def y(*args, **kw): 

743 return render_fn(context, *args, **kw) 

744 

745 try: 

746 y.__name__ = render_fn.__name__[7:] 

747 except TypeError: 

748 # < Python 2.4 

749 pass 

750 return fn(y)(context, *args, **kw) 

751 

752 return go 

753 

754 return decorate_render 

755 

756 

757def _decorate_inline(context, fn): 

758 def decorate_render(render_fn): 

759 dec = fn(render_fn) 

760 

761 def go(*args, **kw): 

762 return dec(context, *args, **kw) 

763 

764 return go 

765 

766 return decorate_render 

767 

768 

769def _include_file(context, uri, calling_uri, **kwargs): 

770 """locate the template from the given uri and include it in 

771 the current output.""" 

772 

773 template = _lookup_template(context, uri, calling_uri) 

774 callable_, ctx = _populate_self_namespace( 

775 context._clean_inheritance_tokens(), template 

776 ) 

777 kwargs = _kwargs_for_include(callable_, context._data, **kwargs) 

778 if template.include_error_handler: 

779 try: 

780 callable_(ctx, **kwargs) 

781 except Exception: 

782 result = template.include_error_handler(ctx, compat.exception_as()) 

783 if not result: 

784 raise 

785 else: 

786 callable_(ctx, **kwargs) 

787 

788 

789def _inherit_from(context, uri, calling_uri): 

790 """called by the _inherit method in template modules to set 

791 up the inheritance chain at the start of a template's 

792 execution.""" 

793 

794 if uri is None: 

795 return None 

796 template = _lookup_template(context, uri, calling_uri) 

797 self_ns = context["self"] 

798 ih = self_ns 

799 while ih.inherits is not None: 

800 ih = ih.inherits 

801 lclcontext = context._locals({"next": ih}) 

802 ih.inherits = TemplateNamespace( 

803 "self:%s" % template.uri, 

804 lclcontext, 

805 template=template, 

806 populate_self=False, 

807 ) 

808 context._data["parent"] = lclcontext._data["local"] = ih.inherits 

809 callable_ = getattr(template.module, "_mako_inherit", None) 

810 if callable_ is not None: 

811 ret = callable_(template, lclcontext) 

812 if ret: 

813 return ret 

814 

815 gen_ns = getattr(template.module, "_mako_generate_namespaces", None) 

816 if gen_ns is not None: 

817 gen_ns(context) 

818 return (template.callable_, lclcontext) 

819 

820 

821def _lookup_template(context, uri, relativeto): 

822 lookup = context._with_template.lookup 

823 if lookup is None: 

824 raise exceptions.TemplateLookupException( 

825 "Template '%s' has no TemplateLookup associated" 

826 % context._with_template.uri 

827 ) 

828 uri = lookup.adjust_uri(uri, relativeto) 

829 try: 

830 return lookup.get_template(uri) 

831 except exceptions.TopLevelLookupException as e: 

832 raise exceptions.TemplateLookupException( 

833 str(compat.exception_as()) 

834 ) from e 

835 

836 

837def _populate_self_namespace(context, template, self_ns=None): 

838 if self_ns is None: 

839 self_ns = TemplateNamespace( 

840 "self:%s" % template.uri, 

841 context, 

842 template=template, 

843 populate_self=False, 

844 ) 

845 context._data["self"] = context._data["local"] = self_ns 

846 if hasattr(template.module, "_mako_inherit"): 

847 ret = template.module._mako_inherit(template, context) 

848 if ret: 

849 return ret 

850 return (template.callable_, context) 

851 

852 

853def _render(template, callable_, args, data, as_unicode=False): 

854 """create a Context and return the string 

855 output of the given template and template callable.""" 

856 

857 if as_unicode: 

858 buf = util.FastEncodingBuffer() 

859 else: 

860 buf = util.FastEncodingBuffer( 

861 encoding=template.output_encoding, errors=template.encoding_errors 

862 ) 

863 context = Context(buf, **data) 

864 context._outputting_as_unicode = as_unicode 

865 context._set_with_template(template) 

866 

867 _render_context( 

868 template, 

869 callable_, 

870 context, 

871 *args, 

872 **_kwargs_for_callable(callable_, data), 

873 ) 

874 return context._pop_buffer().getvalue() 

875 

876 

877def _kwargs_for_callable(callable_, data): 

878 argspec = compat.inspect_getargspec(callable_) 

879 # for normal pages, **pageargs is usually present 

880 if argspec[2]: 

881 return data 

882 

883 # for rendering defs from the top level, figure out the args 

884 namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None] 

885 kwargs = {} 

886 for arg in namedargs: 

887 if arg != "context" and arg in data and arg not in kwargs: 

888 kwargs[arg] = data[arg] 

889 return kwargs 

890 

891 

892def _kwargs_for_include(callable_, data, **kwargs): 

893 argspec = compat.inspect_getargspec(callable_) 

894 namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None] 

895 for arg in namedargs: 

896 if arg != "context" and arg in data and arg not in kwargs: 

897 kwargs[arg] = data[arg] 

898 return kwargs 

899 

900 

901def _render_context(tmpl, callable_, context, *args, **kwargs): 

902 import mako.template as template 

903 

904 # create polymorphic 'self' namespace for this 

905 # template with possibly updated context 

906 if not isinstance(tmpl, template.DefTemplate): 

907 # if main render method, call from the base of the inheritance stack 

908 inherit, lclcontext = _populate_self_namespace(context, tmpl) 

909 _exec_template(inherit, lclcontext, args=args, kwargs=kwargs) 

910 else: 

911 # otherwise, call the actual rendering method specified 

912 inherit, lclcontext = _populate_self_namespace(context, tmpl.parent) 

913 _exec_template(callable_, context, args=args, kwargs=kwargs) 

914 

915 

916def _exec_template(callable_, context, args=None, kwargs=None): 

917 """execute a rendering callable given the callable, a 

918 Context, and optional explicit arguments 

919 

920 the contextual Template will be located if it exists, and 

921 the error handling options specified on that Template will 

922 be interpreted here. 

923 """ 

924 template = context._with_template 

925 if template is not None and ( 

926 template.format_exceptions or template.error_handler 

927 ): 

928 try: 

929 callable_(context, *args, **kwargs) 

930 except Exception: 

931 _render_error(template, context, compat.exception_as()) 

932 except: 

933 e = sys.exc_info()[0] 

934 _render_error(template, context, e) 

935 else: 

936 callable_(context, *args, **kwargs) 

937 

938 

939def _render_error(template, context, error): 

940 if template.error_handler: 

941 result = template.error_handler(context, error) 

942 if not result: 

943 tp, value, tb = sys.exc_info() 

944 if value and tb: 

945 raise value.with_traceback(tb) 

946 else: 

947 raise error 

948 else: 

949 error_template = exceptions.html_error_template() 

950 if context._outputting_as_unicode: 

951 context._buffer_stack[:] = [util.FastEncodingBuffer()] 

952 else: 

953 context._buffer_stack[:] = [ 

954 util.FastEncodingBuffer( 

955 error_template.output_encoding, 

956 error_template.encoding_errors, 

957 ) 

958 ] 

959 

960 context._set_with_template(error_template) 

961 error_template.render_context(context, error=error)