diff genshi/template/base.py @ 703:af57b12e3dd2 experimental-match-fastpaths

merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
author aflett
date Mon, 31 Mar 2008 22:47:50 +0000
parents 3d7288f373bd
children 422d0607ba85
line wrap: on
line diff
--- a/genshi/template/base.py
+++ b/genshi/template/base.py
@@ -255,18 +255,53 @@
         """Pop the top-most scope from the stack."""
 
 
-def _apply_directives(stream, ctxt, directives):
+def _apply_directives(stream, directives, ctxt, **vars):
     """Apply the given directives to the stream.
     
     :param stream: the stream the directives should be applied to
+    :param directives: the list of directives to apply
     :param ctxt: the `Context`
-    :param directives: the list of directives to apply
+    :param vars: additional variables that should be available when Python
+                 code is executed
     :return: the stream with the given directives applied
     """
     if directives:
-        stream = directives[0](iter(stream), ctxt, directives[1:])
+        stream = directives[0](iter(stream), directives[1:], ctxt, **vars)
     return stream
 
+def _eval_expr(expr, ctxt, **vars):
+    """Evaluate the given `Expression` object.
+    
+    :param expr: the expression to evaluate
+    :param ctxt: the `Context`
+    :param vars: additional variables that should be available to the
+                 expression
+    :return: the result of the evaluation
+    """
+    if vars:
+        ctxt.push(vars)
+    retval = expr.evaluate(ctxt)
+    if vars:
+        ctxt.pop()
+    return retval
+
+def _exec_suite(suite, ctxt, **vars):
+    """Execute the given `Suite` object.
+    
+    :param suite: the code suite to execute
+    :param ctxt: the `Context`
+    :param vars: additional variables that should be available to the
+                 code
+    """
+    if vars:
+        ctxt.push(vars)
+        ctxt.push({})
+    suite.execute(_ctxt2dict(ctxt))
+    if vars:
+        top = ctxt.pop()
+        ctxt.pop()
+        ctxt.frames[0].update(top)
+
 
 class TemplateMeta(type):
     """Meta class for templates."""
@@ -427,21 +462,24 @@
         :return: a markup event stream representing the result of applying
                  the template to the context data.
         """
+        vars = {}
         if args:
             assert len(args) == 1
             ctxt = args[0]
             if ctxt is None:
                 ctxt = Context(**kwargs)
+            else:
+                vars = kwargs
             assert isinstance(ctxt, Context)
         else:
             ctxt = Context(**kwargs)
 
         stream = self.stream
         for filter_ in self.filters:
-            stream = filter_(iter(stream), ctxt)
+            stream = filter_(iter(stream), ctxt, **vars)
         return Stream(stream, self.serializer)
 
-    def _eval(self, stream, ctxt):
+    def _eval(self, stream, ctxt, **vars):
         """Internal stream filter that evaluates any expressions in `START` and
         `TEXT` events.
         """
@@ -461,7 +499,8 @@
                     else:
                         values = []
                         for subkind, subdata, subpos in self._eval(substream,
-                                                                   ctxt):
+                                                                   ctxt,
+                                                                   **vars):
                             if subkind is TEXT:
                                 values.append(subdata)
                         value = [x for x in values if x is not None]
@@ -471,7 +510,7 @@
                 yield kind, (tag, Attrs(new_attrs)), pos
 
             elif kind is EXPR:
-                result = data.evaluate(ctxt)
+                result = _eval_expr(data, ctxt, **vars)
                 if result is not None:
                     # First check for a string, otherwise the iterable test
                     # below succeeds, and the string will be chopped up into
@@ -483,7 +522,7 @@
                     elif hasattr(result, '__iter__'):
                         substream = _ensure(result)
                         for filter_ in filters:
-                            substream = filter_(substream, ctxt)
+                            substream = filter_(substream, ctxt, **vars)
                         for event in substream:
                             yield event
                     else:
@@ -492,28 +531,29 @@
             else:
                 yield kind, data, pos
 
-    def _exec(self, stream, ctxt):
+    def _exec(self, stream, ctxt, **vars):
         """Internal stream filter that executes Python code blocks."""
         for event in stream:
             if event[0] is EXEC:
-                event[1].execute(_ctxt2dict(ctxt))
+                _exec_suite(event[1], ctxt, **vars)
             else:
                 yield event
 
-    def _flatten(self, stream, ctxt):
+    def _flatten(self, stream, ctxt, **vars):
         """Internal stream filter that expands `SUB` events in the stream."""
         for event in stream:
             if event[0] is SUB:
                 # This event is a list of directives and a list of nested
                 # events to which those directives should be applied
                 directives, substream = event[1]
-                substream = _apply_directives(substream, ctxt, directives)
-                for event in self._flatten(substream, ctxt):
+                substream = _apply_directives(substream, directives, ctxt,
+                                              **vars)
+                for event in self._flatten(substream, ctxt, **vars):
                     yield event
             else:
                 yield event
 
-    def _include(self, stream, ctxt):
+    def _include(self, stream, ctxt, **vars):
         """Internal stream filter that performs inclusion of external
         template files.
         """
@@ -524,20 +564,21 @@
                 href, cls, fallback = event[1]
                 if not isinstance(href, basestring):
                     parts = []
-                    for subkind, subdata, subpos in self._eval(href, ctxt):
+                    for subkind, subdata, subpos in self._eval(href, ctxt,
+                                                               **vars):
                         if subkind is TEXT:
                             parts.append(subdata)
                     href = u''.join([x for x in parts if x is not None])
                 try:
                     tmpl = self.loader.load(href, relative_to=event[2][0],
                                             cls=cls or self.__class__)
-                    for event in tmpl.generate(ctxt):
+                    for event in tmpl.generate(ctxt, **vars):
                         yield event
                 except TemplateNotFound:
                     if fallback is None:
                         raise
                     for filter_ in self.filters:
-                        fallback = filter_(iter(fallback), ctxt)
+                        fallback = filter_(iter(fallback), ctxt, **vars)
                     for event in fallback:
                         yield event
             else:
Copyright (C) 2012-2017 Edgewall Software