2 # Copyright (C) 2006-2015 the Mako authors and contributors <see AUTHORS file>
4 # This module is part of Mako and is released under
5 # the MIT License: http://www.opensource.org/licenses/mit-license.php
7 """provides runtime services for templates, including Context,
8 Namespace, and various helper functions."""
10 from mako
import exceptions
, util
, compat
11 from mako
.compat
import compat_builtins
15 class Context(object):
16 """Provides runtime namespace, output buffer, and various
17 callstacks for templates.
19 See :ref:`runtime_toplevel` for detail on the usage of
24 def __init__(self
, buffer, **data
):
25 self
._buffer
_stack
= [buffer]
29 self
._kwargs
= data
.copy()
30 self
._with
_template
= None
31 self
._outputting
_as
_unicode
= None
34 # "capture" function which proxies to the
35 # generic "capture" function
36 self
._data
['capture'] = compat
.partial(capture
, self
)
38 # "caller" stack used by def calls with content
39 self
.caller_stack
= self
._data
['caller'] = CallerStack()
41 def _set_with_template(self
, t
):
42 self
._with
_template
= t
43 illegal_names
= t
.reserved_names
.intersection(self
._data
)
45 raise exceptions
.NameConflictError(
46 "Reserved words passed to render(): %s" %
47 ", ".join(illegal_names
))
51 """Return the :class:`.TemplateLookup` associated
52 with this :class:`.Context`.
55 return self
._with
_template
.lookup
59 """Return the dictionary of top level keyword arguments associated
60 with this :class:`.Context`.
62 This dictionary only includes the top-level arguments passed to
63 :meth:`.Template.render`. It does not include names produced within
64 the template execution such as local variable names or special names
65 such as ``self``, ``next``, etc.
67 The purpose of this dictionary is primarily for the case that
68 a :class:`.Template` accepts arguments via its ``<%page>`` tag,
69 which are normally expected to be passed via :meth:`.Template.render`,
70 except the template is being called in an inheritance context,
71 using the ``body()`` method. :attr:`.Context.kwargs` can then be
72 used to propagate these arguments to the inheriting template::
74 ${next.body(**context.kwargs)}
77 return self
._kwargs
.copy()
79 def push_caller(self
, caller
):
80 """Push a ``caller`` callable onto the callstack for
81 this :class:`.Context`."""
84 self
.caller_stack
.append(caller
)
87 """Pop a ``caller`` callable onto the callstack for this
90 del self
.caller_stack
[-1]
93 """Return a list of all names established in this :class:`.Context`."""
95 return list(self
._data
.keys())
97 def __getitem__(self
, key
):
99 return self
._data
[key
]
101 return compat_builtins
.__dict
__[key
]
103 def _push_writer(self
):
104 """push a capturing buffer onto this Context and return
105 the new writer function."""
107 buf
= util
.FastEncodingBuffer()
108 self
._buffer
_stack
.append(buf
)
111 def _pop_buffer_and_writer(self
):
112 """pop the most recent capturing buffer from this Context
113 and return the current writer after the pop.
117 buf
= self
._buffer
_stack
.pop()
118 return buf
, self
._buffer
_stack
[-1].write
120 def _push_buffer(self
):
121 """push a capturing buffer onto this Context."""
125 def _pop_buffer(self
):
126 """pop the most recent capturing buffer from this Context."""
128 return self
._buffer
_stack
.pop()
130 def get(self
, key
, default
=None):
131 """Return a value from this :class:`.Context`."""
133 return self
._data
.get(key
, compat_builtins
.__dict
__.get(key
, default
))
135 def write(self
, string
):
136 """Write a string to this :class:`.Context` object's
137 underlying output buffer."""
139 self
._buffer
_stack
[-1].write(string
)
142 """Return the current writer function."""
144 return self
._buffer
_stack
[-1].write
147 c
= Context
.__new
__(Context
)
148 c
._buffer
_stack
= self
._buffer
_stack
149 c
._data
= self
._data
.copy()
150 c
._kwargs
= self
._kwargs
151 c
._with
_template
= self
._with
_template
152 c
._outputting
_as
_unicode
= self
._outputting
_as
_unicode
153 c
.namespaces
= self
.namespaces
154 c
.caller_stack
= self
.caller_stack
157 def _locals(self
, d
):
158 """Create a new :class:`.Context` with a copy of this
159 :class:`.Context`'s current state,
160 updated with the given dictionary.
162 The :attr:`.Context.kwargs` collection remains
174 def _clean_inheritance_tokens(self
):
175 """create a new copy of this :class:`.Context`. with
176 tokens related to inheritance state removed."""
181 x
.pop('parent', None)
185 class CallerStack(list):
187 self
.nextcaller
= None
189 def __nonzero__(self
):
190 return self
.__bool
__()
193 return len(self
) and self
._get
_caller
() and True or False
195 def _get_caller(self
):
196 # this method can be removed once
197 # codegen MAGIC_NUMBER moves past 7
200 def __getattr__(self
, key
):
201 return getattr(self
._get
_caller
(), key
)
203 def _push_frame(self
):
204 frame
= self
.nextcaller
or None
206 self
.nextcaller
= None
209 def _pop_frame(self
):
210 self
.nextcaller
= self
.pop()
213 class Undefined(object):
214 """Represents an undefined value in a template.
216 All template modules have a constant value
217 ``UNDEFINED`` present which is an instance of this
222 raise NameError("Undefined")
224 def __nonzero__(self
):
225 return self
.__bool
__()
230 UNDEFINED
= Undefined()
232 class LoopStack(object):
233 """a stack for LoopContexts that implements the context manager protocol
234 to automatically pop off the top of the stack on context exit
240 def _enter(self
, iterable
):
251 return self
.stack
[-1]
256 return self
.stack
.pop()
258 def _push(self
, iterable
):
259 new
= LoopContext(iterable
)
261 new
.parent
= self
.stack
[-1]
262 return self
.stack
.append(new
)
264 def __getattr__(self
, key
):
265 raise exceptions
.RuntimeException("No loop context is established")
268 return iter(self
._top
)
271 class LoopContext(object):
272 """A magic loop variable.
273 Automatically accessible in any ``% for`` block.
275 See the section :ref:`loop_context` for usage
278 :attr:`parent` -> :class:`.LoopContext` or ``None``
279 The parent loop, if one exists.
280 :attr:`index` -> `int`
281 The 0-based iteration count.
282 :attr:`reverse_index` -> `int`
283 The number of iterations remaining.
284 :attr:`first` -> `bool`
285 ``True`` on the first iteration, ``False`` otherwise.
286 :attr:`last` -> `bool`
287 ``True`` on the last iteration, ``False`` otherwise.
288 :attr:`even` -> `bool`
289 ``True`` when ``index`` is even.
290 :attr:`odd` -> `bool`
291 ``True`` when ``index`` is odd.
294 def __init__(self
, iterable
):
295 self
._iterable
= iterable
300 for i
in self
._iterable
:
304 @util.memoized_instancemethod
306 return len(self
._iterable
)
309 def reverse_index(self
):
310 return len(self
) - self
.index
- 1
314 return self
.index
== 0
318 return self
.index
== len(self
) - 1
326 return bool(self
.index
% 2)
328 def cycle(self
, *values
):
329 """Cycle through values as the loop progresses.
332 raise ValueError("You must provide values to cycle through")
333 return values
[self
.index
% len(values
)]
336 class _NSAttr(object):
337 def __init__(self
, parent
):
338 self
.__parent
= parent
339 def __getattr__(self
, key
):
342 if hasattr(ns
.module
, key
):
343 return getattr(ns
.module
, key
)
346 raise AttributeError(key
)
348 class Namespace(object):
349 """Provides access to collections of rendering methods, which
350 can be local, from other templates, or from imported modules.
352 To access a particular rendering method referenced by a
353 :class:`.Namespace`, use plain attribute access:
357 ${some_namespace.foo(x, y, z)}
359 :class:`.Namespace` also contains several built-in attributes
364 def __init__(self
, name
, context
,
365 callables
=None, inherits
=None,
366 populate_self
=True, calling_uri
=None):
368 self
.context
= context
369 self
.inherits
= inherits
370 if callables
is not None:
371 self
.callables
= dict([(c
.__name
__, c
) for c
in callables
])
376 """The Python module referenced by this :class:`.Namespace`.
378 If the namespace references a :class:`.Template`, then
379 this module is the equivalent of ``template.module``,
380 i.e. the generated module for the template.
385 """The :class:`.Template` object referenced by this
386 :class:`.Namespace`, if any.
391 """The :class:`.Context` object for this :class:`.Namespace`.
393 Namespaces are often created with copies of contexts that
394 contain slightly different data, particularly in inheritance
395 scenarios. Using the :class:`.Context` off of a :class:`.Namespace` one
396 can traverse an entire chain of templates that inherit from
402 """The path of the filesystem file used for this
403 :class:`.Namespace`'s module or template.
405 If this is a pure module-based
406 :class:`.Namespace`, this evaluates to ``module.__file__``. If a
407 template-based namespace, it evaluates to the original
408 template file location.
413 """The URI for this :class:`.Namespace`'s template.
415 I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
417 This is the equivalent of :attr:`.Template.uri`.
423 @util.memoized_property
425 """Access module level attributes by name.
427 This accessor allows templates to supply "scalar"
428 attributes which are particularly handy in inheritance
433 :ref:`inheritance_attr`
435 :ref:`namespace_attr_for_includes`
440 def get_namespace(self
, uri
):
441 """Return a :class:`.Namespace` corresponding to the given ``uri``.
443 If the given ``uri`` is a relative URI (i.e. it does not
444 contain a leading slash ``/``), the ``uri`` is adjusted to
445 be relative to the ``uri`` of the namespace itself. This
446 method is therefore mostly useful off of the built-in
447 ``local`` namespace, described in :ref:`namespace_local`.
450 most cases, a template wouldn't need this function, and
451 should instead use the ``<%namespace>`` tag to load
452 namespaces. However, since all ``<%namespace>`` tags are
453 evaluated before the body of a template ever runs,
454 this method can be used to locate namespaces using
455 expressions that were generated within the body code of
456 the template, or to conditionally use a particular
461 if key
in self
.context
.namespaces
:
462 return self
.context
.namespaces
[key
]
464 ns
= TemplateNamespace(uri
, self
.context
._copy
(),
466 calling_uri
=self
._templateuri
)
467 self
.context
.namespaces
[key
] = ns
470 def get_template(self
, uri
):
471 """Return a :class:`.Template` from the given ``uri``.
473 The ``uri`` resolution is relative to the ``uri`` of this
474 :class:`.Namespace` object's :class:`.Template`.
477 return _lookup_template(self
.context
, uri
, self
._templateuri
)
479 def get_cached(self
, key
, **kwargs
):
480 """Return a value from the :class:`.Cache` referenced by this
481 :class:`.Namespace` object's :class:`.Template`.
483 The advantage to this method versus direct access to the
484 :class:`.Cache` is that the configuration parameters
485 declared in ``<%page>`` take effect here, thereby calling
486 up the same configured backend as that configured
491 return self
.cache
.get(key
, **kwargs
)
495 """Return the :class:`.Cache` object referenced
496 by this :class:`.Namespace` object's
500 return self
.template
.cache
502 def include_file(self
, uri
, **kwargs
):
503 """Include a file at the given ``uri``."""
505 _include_file(self
.context
, uri
, self
._templateuri
, **kwargs
)
507 def _populate(self
, d
, l
):
510 for (k
, v
) in self
._get
_star
():
513 d
[ident
] = getattr(self
, ident
)
517 for key
in self
.callables
:
518 yield (key
, self
.callables
[key
])
520 def __getattr__(self
, key
):
521 if key
in self
.callables
:
522 val
= self
.callables
[key
]
524 val
= getattr(self
.inherits
, key
)
526 raise AttributeError(
527 "Namespace '%s' has no member '%s'" %
529 setattr(self
, key
, val
)
532 class TemplateNamespace(Namespace
):
533 """A :class:`.Namespace` specific to a :class:`.Template` instance."""
535 def __init__(self
, name
, context
, template
=None, templateuri
=None,
536 callables
=None, inherits
=None,
537 populate_self
=True, calling_uri
=None):
539 self
.context
= context
540 self
.inherits
= inherits
541 if callables
is not None:
542 self
.callables
= dict([(c
.__name
__, c
) for c
in callables
])
544 if templateuri
is not None:
545 self
.template
= _lookup_template(context
, templateuri
,
547 self
._templateuri
= self
.template
.module
._template
_uri
548 elif template
is not None:
549 self
.template
= template
550 self
._templateuri
= template
.module
._template
_uri
552 raise TypeError("'template' argument is required.")
555 lclcallable
, lclcontext
= \
556 _populate_self_namespace(context
, self
.template
,
561 """The Python module referenced by this :class:`.Namespace`.
563 If the namespace references a :class:`.Template`, then
564 this module is the equivalent of ``template.module``,
565 i.e. the generated module for the template.
568 return self
.template
.module
572 """The path of the filesystem file used for this
573 :class:`.Namespace`'s module or template.
575 return self
.template
.filename
579 """The URI for this :class:`.Namespace`'s template.
581 I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
583 This is the equivalent of :attr:`.Template.uri`.
586 return self
.template
.uri
590 for key
in self
.callables
:
591 yield (key
, self
.callables
[key
])
593 callable_
= self
.template
._get
_def
_callable
(key
)
594 return compat
.partial(callable_
, self
.context
)
595 for k
in self
.template
.module
._exports
:
598 def __getattr__(self
, key
):
599 if key
in self
.callables
:
600 val
= self
.callables
[key
]
601 elif self
.template
.has_def(key
):
602 callable_
= self
.template
._get
_def
_callable
(key
)
603 val
= compat
.partial(callable_
, self
.context
)
605 val
= getattr(self
.inherits
, key
)
608 raise AttributeError(
609 "Namespace '%s' has no member '%s'" %
611 setattr(self
, key
, val
)
614 class ModuleNamespace(Namespace
):
615 """A :class:`.Namespace` specific to a Python module instance."""
617 def __init__(self
, name
, context
, module
,
618 callables
=None, inherits
=None,
619 populate_self
=True, calling_uri
=None):
621 self
.context
= context
622 self
.inherits
= inherits
623 if callables
is not None:
624 self
.callables
= dict([(c
.__name
__, c
) for c
in callables
])
626 mod
= __import__(module
)
627 for token
in module
.split('.')[1:]:
628 mod
= getattr(mod
, token
)
633 """The path of the filesystem file used for this
634 :class:`.Namespace`'s module or template.
636 return self
.module
.__file
__
640 for key
in self
.callables
:
641 yield (key
, self
.callables
[key
])
642 for key
in dir(self
.module
):
644 callable_
= getattr(self
.module
, key
)
645 if compat
.callable(callable_
):
646 yield key
, compat
.partial(callable_
, self
.context
)
649 def __getattr__(self
, key
):
650 if key
in self
.callables
:
651 val
= self
.callables
[key
]
652 elif hasattr(self
.module
, key
):
653 callable_
= getattr(self
.module
, key
)
654 val
= compat
.partial(callable_
, self
.context
)
656 val
= getattr(self
.inherits
, key
)
658 raise AttributeError(
659 "Namespace '%s' has no member '%s'" %
661 setattr(self
, key
, val
)
664 def supports_caller(func
):
665 """Apply a caller_stack compatibility decorator to a plain
668 See the example in :ref:`namespaces_python_modules`.
672 def wrap_stackframe(context
, *args
, **kwargs
):
673 context
.caller_stack
._push
_frame
()
675 return func(context
, *args
, **kwargs
)
677 context
.caller_stack
._pop
_frame
()
678 return wrap_stackframe
680 def capture(context
, callable_
, *args
, **kwargs
):
681 """Execute the given template def, capturing the output into
684 See the example in :ref:`namespaces_python_modules`.
688 if not compat
.callable(callable_
):
689 raise exceptions
.RuntimeException(
690 "capture() function expects a callable as "
691 "its argument (i.e. capture(func, *args, **kwargs))"
693 context
._push
_buffer
()
695 callable_(*args
, **kwargs
)
697 buf
= context
._pop
_buffer
()
698 return buf
.getvalue()
700 def _decorate_toplevel(fn
):
701 def decorate_render(render_fn
):
702 def go(context
, *args
, **kw
):
704 return render_fn(context
, *args
, **kw
)
706 y
.__name
__ = render_fn
.__name
__[7:]
710 return fn(y
)(context
, *args
, **kw
)
712 return decorate_render
714 def _decorate_inline(context
, fn
):
715 def decorate_render(render_fn
):
718 return dec(context
, *args
, **kw
)
720 return decorate_render
722 def _include_file(context
, uri
, calling_uri
, **kwargs
):
723 """locate the template from the given uri and include it in
724 the current output."""
726 template
= _lookup_template(context
, uri
, calling_uri
)
727 (callable_
, ctx
) = _populate_self_namespace(
728 context
._clean
_inheritance
_tokens
(),
730 callable_(ctx
, **_kwargs_for_include(callable_
, context
._data
, **kwargs
))
732 def _inherit_from(context
, uri
, calling_uri
):
733 """called by the _inherit method in template modules to set
734 up the inheritance chain at the start of a template's
739 template
= _lookup_template(context
, uri
, calling_uri
)
740 self_ns
= context
['self']
742 while ih
.inherits
is not None:
744 lclcontext
= context
._locals
({'next': ih
})
745 ih
.inherits
= TemplateNamespace("self:%s" % template
.uri
,
749 context
._data
['parent'] = lclcontext
._data
['local'] = ih
.inherits
750 callable_
= getattr(template
.module
, '_mako_inherit', None)
751 if callable_
is not None:
752 ret
= callable_(template
, lclcontext
)
756 gen_ns
= getattr(template
.module
, '_mako_generate_namespaces', None)
757 if gen_ns
is not None:
759 return (template
.callable_
, lclcontext
)
761 def _lookup_template(context
, uri
, relativeto
):
762 lookup
= context
._with
_template
.lookup
764 raise exceptions
.TemplateLookupException(
765 "Template '%s' has no TemplateLookup associated" %
766 context
._with
_template
.uri
)
767 uri
= lookup
.adjust_uri(uri
, relativeto
)
769 return lookup
.get_template(uri
)
770 except exceptions
.TopLevelLookupException
:
771 raise exceptions
.TemplateLookupException(str(compat
.exception_as()))
773 def _populate_self_namespace(context
, template
, self_ns
=None):
775 self_ns
= TemplateNamespace('self:%s' % template
.uri
,
776 context
, template
=template
,
778 context
._data
['self'] = context
._data
['local'] = self_ns
779 if hasattr(template
.module
, '_mako_inherit'):
780 ret
= template
.module
._mako
_inherit
(template
, context
)
783 return (template
.callable_
, context
)
785 def _render(template
, callable_
, args
, data
, as_unicode
=False):
786 """create a Context and return the string
787 output of the given template and template callable."""
790 buf
= util
.FastEncodingBuffer(as_unicode
=True)
791 elif template
.bytestring_passthrough
:
792 buf
= compat
.StringIO()
794 buf
= util
.FastEncodingBuffer(
795 as_unicode
=as_unicode
,
796 encoding
=template
.output_encoding
,
797 errors
=template
.encoding_errors
)
798 context
= Context(buf
, **data
)
799 context
._outputting
_as
_unicode
= as_unicode
800 context
._set
_with
_template
(template
)
802 _render_context(template
, callable_
, context
, *args
,
803 **_kwargs_for_callable(callable_
, data
))
804 return context
._pop
_buffer
().getvalue()
806 def _kwargs_for_callable(callable_
, data
):
807 argspec
= compat
.inspect_func_args(callable_
)
808 # for normal pages, **pageargs is usually present
812 # for rendering defs from the top level, figure out the args
813 namedargs
= argspec
[0] + [v
for v
in argspec
[1:3] if v
is not None]
815 for arg
in namedargs
:
816 if arg
!= 'context' and arg
in data
and arg
not in kwargs
:
817 kwargs
[arg
] = data
[arg
]
820 def _kwargs_for_include(callable_
, data
, **kwargs
):
821 argspec
= compat
.inspect_func_args(callable_
)
822 namedargs
= argspec
[0] + [v
for v
in argspec
[1:3] if v
is not None]
823 for arg
in namedargs
:
824 if arg
!= 'context' and arg
in data
and arg
not in kwargs
:
825 kwargs
[arg
] = data
[arg
]
828 def _render_context(tmpl
, callable_
, context
, *args
, **kwargs
):
829 import mako
.template
as template
830 # create polymorphic 'self' namespace for this
831 # template with possibly updated context
832 if not isinstance(tmpl
, template
.DefTemplate
):
833 # if main render method, call from the base of the inheritance stack
834 (inherit
, lclcontext
) = _populate_self_namespace(context
, tmpl
)
835 _exec_template(inherit
, lclcontext
, args
=args
, kwargs
=kwargs
)
837 # otherwise, call the actual rendering method specified
838 (inherit
, lclcontext
) = _populate_self_namespace(context
, tmpl
.parent
)
839 _exec_template(callable_
, context
, args
=args
, kwargs
=kwargs
)
841 def _exec_template(callable_
, context
, args
=None, kwargs
=None):
842 """execute a rendering callable given the callable, a
843 Context, and optional explicit arguments
845 the contextual Template will be located if it exists, and
846 the error handling options specified on that Template will
849 template
= context
._with
_template
850 if template
is not None and \
851 (template
.format_exceptions
or template
.error_handler
):
853 callable_(context
, *args
, **kwargs
)
855 _render_error(template
, context
, compat
.exception_as())
857 e
= sys
.exc_info()[0]
858 _render_error(template
, context
, e
)
860 callable_(context
, *args
, **kwargs
)
862 def _render_error(template
, context
, error
):
863 if template
.error_handler
:
864 result
= template
.error_handler(context
, error
)
866 compat
.reraise(*sys
.exc_info())
868 error_template
= exceptions
.html_error_template()
869 if context
._outputting
_as
_unicode
:
870 context
._buffer
_stack
[:] = [
871 util
.FastEncodingBuffer(as_unicode
=True)]
873 context
._buffer
_stack
[:] = [util
.FastEncodingBuffer(
874 error_template
.output_encoding
,
875 error_template
.encoding_errors
)]
877 context
._set
_with
_template
(error_template
)
878 error_template
.render_context(context
, error
=error
)