Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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 functools 

11import sys 

12 

13from mako import compat 

14from mako import exceptions 

15from mako import util 

16from mako.compat import compat_builtins 

17 

18 

19class Context(object): 

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 compat_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, compat_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(object): 

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(object): 

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(object): 

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 """ 

344 if not values: 

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

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

347 

348 

349class _NSAttr(object): 

350 def __init__(self, parent): 

351 self.__parent = parent 

352 

353 def __getattr__(self, key): 

354 ns = self.__parent 

355 while ns: 

356 if hasattr(ns.module, key): 

357 return getattr(ns.module, key) 

358 else: 

359 ns = ns.inherits 

360 raise AttributeError(key) 

361 

362 

363class Namespace(object): 

364 

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

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

367 

368 To access a particular rendering method referenced by a 

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

370 

371 .. sourcecode:: mako 

372 

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

374 

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

376 described here. 

377 

378 """ 

379 

380 def __init__( 

381 self, 

382 name, 

383 context, 

384 callables=None, 

385 inherits=None, 

386 populate_self=True, 

387 calling_uri=None, 

388 ): 

389 self.name = name 

390 self.context = context 

391 self.inherits = inherits 

392 if callables is not None: 

393 self.callables = dict([(c.__name__, c) for c in callables]) 

394 

395 callables = () 

396 

397 module = None 

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

399 

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

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

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

403 

404 """ 

405 

406 template = None 

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

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

409 

410 """ 

411 

412 context = None 

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

414 

415 Namespaces are often created with copies of contexts that 

416 contain slightly different data, particularly in inheritance 

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

418 can traverse an entire chain of templates that inherit from 

419 one-another. 

420 

421 """ 

422 

423 filename = None 

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

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

426 

427 If this is a pure module-based 

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

429 template-based namespace, it evaluates to the original 

430 template file location. 

431 

432 """ 

433 

434 uri = None 

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

436 

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

438 

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

440 

441 """ 

442 

443 _templateuri = None 

444 

445 @util.memoized_property 

446 def attr(self): 

447 """Access module level attributes by name. 

448 

449 This accessor allows templates to supply "scalar" 

450 attributes which are particularly handy in inheritance 

451 relationships. 

452 

453 .. seealso:: 

454 

455 :ref:`inheritance_attr` 

456 

457 :ref:`namespace_attr_for_includes` 

458 

459 """ 

460 return _NSAttr(self) 

461 

462 def get_namespace(self, uri): 

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

464 

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

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

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

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

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

470 

471 In 

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

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

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

475 evaluated before the body of a template ever runs, 

476 this method can be used to locate namespaces using 

477 expressions that were generated within the body code of 

478 the template, or to conditionally use a particular 

479 namespace. 

480 

481 """ 

482 key = (self, uri) 

483 if key in self.context.namespaces: 

484 return self.context.namespaces[key] 

485 else: 

486 ns = TemplateNamespace( 

487 uri, 

488 self.context._copy(), 

489 templateuri=uri, 

490 calling_uri=self._templateuri, 

491 ) 

492 self.context.namespaces[key] = ns 

493 return ns 

494 

495 def get_template(self, uri): 

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

497 

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

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

500 

501 """ 

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

503 

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

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

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

507 

508 The advantage to this method versus direct access to the 

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

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

511 up the same configured backend as that configured 

512 by ``<%page>``. 

513 

514 """ 

515 

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

517 

518 @property 

519 def cache(self): 

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

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

522 :class:`.Template`. 

523 

524 """ 

525 return self.template.cache 

526 

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

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

529 

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

531 

532 def _populate(self, d, l): 

533 for ident in l: 

534 if ident == "*": 

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

536 d[k] = v 

537 else: 

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

539 

540 def _get_star(self): 

541 if self.callables: 

542 for key in self.callables: 

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

544 

545 def __getattr__(self, key): 

546 if key in self.callables: 

547 val = self.callables[key] 

548 elif self.inherits: 

549 val = getattr(self.inherits, key) 

550 else: 

551 raise AttributeError( 

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

553 ) 

554 setattr(self, key, val) 

555 return val 

556 

557 

558class TemplateNamespace(Namespace): 

559 

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

561 

562 def __init__( 

563 self, 

564 name, 

565 context, 

566 template=None, 

567 templateuri=None, 

568 callables=None, 

569 inherits=None, 

570 populate_self=True, 

571 calling_uri=None, 

572 ): 

573 self.name = name 

574 self.context = context 

575 self.inherits = inherits 

576 if callables is not None: 

577 self.callables = dict([(c.__name__, c) for c in callables]) 

578 

579 if templateuri is not None: 

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

581 self._templateuri = self.template.module._template_uri 

582 elif template is not None: 

583 self.template = template 

584 self._templateuri = template.module._template_uri 

585 else: 

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

587 

588 if populate_self: 

589 lclcallable, lclcontext = _populate_self_namespace( 

590 context, self.template, self_ns=self 

591 ) 

592 

593 @property 

594 def module(self): 

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

596 

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

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

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

600 

601 """ 

602 return self.template.module 

603 

604 @property 

605 def filename(self): 

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

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

608 """ 

609 return self.template.filename 

610 

611 @property 

612 def uri(self): 

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

614 

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

616 

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

618 

619 """ 

620 return self.template.uri 

621 

622 def _get_star(self): 

623 if self.callables: 

624 for key in self.callables: 

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

626 

627 def get(key): 

628 callable_ = self.template._get_def_callable(key) 

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

630 

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

632 yield (k, get(k)) 

633 

634 def __getattr__(self, key): 

635 if key in self.callables: 

636 val = self.callables[key] 

637 elif self.template.has_def(key): 

638 callable_ = self.template._get_def_callable(key) 

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

640 elif self.inherits: 

641 val = getattr(self.inherits, key) 

642 

643 else: 

644 raise AttributeError( 

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

646 ) 

647 setattr(self, key, val) 

648 return val 

649 

650 

651class ModuleNamespace(Namespace): 

652 

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

654 

655 def __init__( 

656 self, 

657 name, 

658 context, 

659 module, 

660 callables=None, 

661 inherits=None, 

662 populate_self=True, 

663 calling_uri=None, 

664 ): 

665 self.name = name 

666 self.context = context 

667 self.inherits = inherits 

668 if callables is not None: 

669 self.callables = dict([(c.__name__, c) for c in callables]) 

670 

671 mod = __import__(module) 

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

673 mod = getattr(mod, token) 

674 self.module = mod 

675 

676 @property 

677 def filename(self): 

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

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

680 """ 

681 return self.module.__file__ 

682 

683 def _get_star(self): 

684 if self.callables: 

685 for key in self.callables: 

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

687 for key in dir(self.module): 

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

689 callable_ = getattr(self.module, key) 

690 if callable(callable_): 

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

692 

693 def __getattr__(self, key): 

694 if key in self.callables: 

695 val = self.callables[key] 

696 elif hasattr(self.module, key): 

697 callable_ = getattr(self.module, key) 

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

699 elif self.inherits: 

700 val = getattr(self.inherits, key) 

701 else: 

702 raise AttributeError( 

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

704 ) 

705 setattr(self, key, val) 

706 return val 

707 

708 

709def supports_caller(func): 

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

711 Python function. 

712 

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

714 

715 """ 

716 

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

718 context.caller_stack._push_frame() 

719 try: 

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

721 finally: 

722 context.caller_stack._pop_frame() 

723 

724 return wrap_stackframe 

725 

726 

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

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

729 a buffer. 

730 

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

732 

733 """ 

734 

735 if not callable(callable_): 

736 raise exceptions.RuntimeException( 

737 "capture() function expects a callable as " 

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

739 ) 

740 context._push_buffer() 

741 try: 

742 callable_(*args, **kwargs) 

743 finally: 

744 buf = context._pop_buffer() 

745 return buf.getvalue() 

746 

747 

748def _decorate_toplevel(fn): 

749 def decorate_render(render_fn): 

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

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

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

753 

754 try: 

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

756 except TypeError: 

757 # < Python 2.4 

758 pass 

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

760 

761 return go 

762 

763 return decorate_render 

764 

765 

766def _decorate_inline(context, fn): 

767 def decorate_render(render_fn): 

768 dec = fn(render_fn) 

769 

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

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

772 

773 return go 

774 

775 return decorate_render 

776 

777 

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

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

780 the current output.""" 

781 

782 template = _lookup_template(context, uri, calling_uri) 

783 (callable_, ctx) = _populate_self_namespace( 

784 context._clean_inheritance_tokens(), template 

785 ) 

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

787 if template.include_error_handler: 

788 try: 

789 callable_(ctx, **kwargs) 

790 except Exception: 

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

792 if not result: 

793 compat.reraise(*sys.exc_info()) 

794 else: 

795 callable_(ctx, **kwargs) 

796 

797 

798def _inherit_from(context, uri, calling_uri): 

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

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

801 execution.""" 

802 

803 if uri is None: 

804 return None 

805 template = _lookup_template(context, uri, calling_uri) 

806 self_ns = context["self"] 

807 ih = self_ns 

808 while ih.inherits is not None: 

809 ih = ih.inherits 

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

811 ih.inherits = TemplateNamespace( 

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

813 lclcontext, 

814 template=template, 

815 populate_self=False, 

816 ) 

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

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

819 if callable_ is not None: 

820 ret = callable_(template, lclcontext) 

821 if ret: 

822 return ret 

823 

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

825 if gen_ns is not None: 

826 gen_ns(context) 

827 return (template.callable_, lclcontext) 

828 

829 

830def _lookup_template(context, uri, relativeto): 

831 lookup = context._with_template.lookup 

832 if lookup is None: 

833 raise exceptions.TemplateLookupException( 

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

835 % context._with_template.uri 

836 ) 

837 uri = lookup.adjust_uri(uri, relativeto) 

838 try: 

839 return lookup.get_template(uri) 

840 except exceptions.TopLevelLookupException: 

841 raise exceptions.TemplateLookupException(str(compat.exception_as())) 

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(as_unicode=True) 

866 elif template.bytestring_passthrough: 

867 buf = compat.StringIO() 

868 else: 

869 buf = util.FastEncodingBuffer( 

870 as_unicode=as_unicode, 

871 encoding=template.output_encoding, 

872 errors=template.encoding_errors, 

873 ) 

874 context = Context(buf, **data) 

875 context._outputting_as_unicode = as_unicode 

876 context._set_with_template(template) 

877 

878 _render_context( 

879 template, 

880 callable_, 

881 context, 

882 *args, 

883 **_kwargs_for_callable(callable_, data) 

884 ) 

885 return context._pop_buffer().getvalue() 

886 

887 

888def _kwargs_for_callable(callable_, data): 

889 argspec = compat.inspect_getargspec(callable_) 

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

891 if argspec[2]: 

892 return data 

893 

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

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

896 kwargs = {} 

897 for arg in namedargs: 

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

899 kwargs[arg] = data[arg] 

900 return kwargs 

901 

902 

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

904 argspec = compat.inspect_getargspec(callable_) 

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

906 for arg in namedargs: 

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

908 kwargs[arg] = data[arg] 

909 return kwargs 

910 

911 

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

913 import mako.template as template 

914 

915 # create polymorphic 'self' namespace for this 

916 # template with possibly updated context 

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

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

919 (inherit, lclcontext) = _populate_self_namespace(context, tmpl) 

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

921 else: 

922 # otherwise, call the actual rendering method specified 

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

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

925 

926 

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

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

929 Context, and optional explicit arguments 

930 

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

932 the error handling options specified on that Template will 

933 be interpreted here. 

934 """ 

935 template = context._with_template 

936 if template is not None and ( 

937 template.format_exceptions or template.error_handler 

938 ): 

939 try: 

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

941 except Exception: 

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

943 except: 

944 e = sys.exc_info()[0] 

945 _render_error(template, context, e) 

946 else: 

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

948 

949 

950def _render_error(template, context, error): 

951 if template.error_handler: 

952 result = template.error_handler(context, error) 

953 if not result: 

954 compat.reraise(*sys.exc_info()) 

955 else: 

956 error_template = exceptions.html_error_template() 

957 if context._outputting_as_unicode: 

958 context._buffer_stack[:] = [ 

959 util.FastEncodingBuffer(as_unicode=True) 

960 ] 

961 else: 

962 context._buffer_stack[:] = [ 

963 util.FastEncodingBuffer( 

964 error_template.output_encoding, 

965 error_template.encoding_errors, 

966 ) 

967 ] 

968 

969 context._set_with_template(error_template) 

970 error_template.render_context(context, error=error)