changeset 149:537f819c547b trunk

`Template.generate()` now accepts the context data as keyword arguments, so that you don't have to import the `Context` class every time you want to pass data into a template.
author cmlenz
date Tue, 15 Aug 2006 21:59:07 +0000
parents dcc9dc25bc59
children d35688d16831
files COPYING examples/basic/run.py examples/bench/basic.py examples/bench/bigtable.py markup/plugin.py markup/template.py markup/tests/template.py
diffstat 7 files changed, 53 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (C) 2006 Christopher Lenz
+Copyright (C) 2006 Edgewall Software
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
--- a/examples/basic/run.py
+++ b/examples/basic/run.py
@@ -5,7 +5,7 @@
 import sys
 import time
 
-from markup.template import Context, TemplateLoader
+from markup.template import TemplateLoader
 
 def test():
     base_path = os.path.dirname(os.path.abspath(__file__))
@@ -19,12 +19,12 @@
                 items=['Number %d' % num for num in range(1, 15)],
                 prefix='#')
 
-    print tmpl.generate(Context(**data)).render(method='html')
+    print tmpl.generate(**data).render(method='html')
 
     times = []
     for i in range(1000):
         start = time.clock()
-        list(tmpl.generate(Context(**data)))
+        list(tmpl.generate(**data))
         times.append(time.clock() - start)
         sys.stdout.write('.')
         sys.stdout.flush()
--- a/examples/bench/basic.py
+++ b/examples/bench/basic.py
@@ -7,13 +7,13 @@
 __all__ = ['clearsilver', 'django', 'kid', 'markup', 'simpletal']
 
 def markup(dirname, verbose=False):
-    from markup.template import Context, TemplateLoader
+    from markup.template import TemplateLoader
     loader = TemplateLoader([dirname], auto_reload=False)
     template = loader.load('template.html')
     def render():
-        ctxt = Context(title='Just a test', user='joe',
-                       items=['Number %d' % num for num in range(1, 15)])
-        return template.generate(ctxt).render('xhtml')
+        data = dict(title='Just a test', user='joe',
+                    items=['Number %d' % num for num in range(1, 15)])
+        return template.generate(**data).render('xhtml')
 
     if verbose:
         print render()
--- a/examples/bench/bigtable.py
+++ b/examples/bench/bigtable.py
@@ -12,7 +12,7 @@
 import cElementTree as cet
 from elementtree import ElementTree as et
 from markup.builder import tag
-from markup.template import Context, Template
+from markup.template import Template
 import neo_cgi
 import neo_cs
 import neo_util
@@ -66,8 +66,7 @@
 
 def test_markup():
     """Markup template"""
-    ctxt = Context(table=table)
-    stream = markup_tmpl.generate(ctxt)
+    stream = markup_tmpl.generate(table=table)
     stream.render('html', strip_whitespace=False)
 
 def test_markup_builder():
@@ -76,8 +75,7 @@
         tag.tr([tag.td(c) for c in row.values()])
         for row in table
     ]).generate()
-    ctxt = Context(table=stream)
-    stream = markup_tmpl2.generate(ctxt)
+    stream = markup_tmpl2.generate(table=stream)
     stream.render('html', strip_whitespace=False)
 
 def test_builder():
--- a/markup/plugin.py
+++ b/markup/plugin.py
@@ -75,5 +75,4 @@
             data.update(self.get_extra_vars())
         data.update(info)
 
-        ctxt = Context(**data)
-        return template.generate(ctxt)
+        return template.generate(**data)
--- a/markup/template.py
+++ b/markup/template.py
@@ -31,8 +31,7 @@
 from markup.input import XMLParser
 from markup.path import Path
 
-__all__ = ['Context', 'BadDirectiveError', 'TemplateError',
-           'TemplateSyntaxError', 'TemplateNotFound', 'Template',
+__all__ = ['TemplateSyntaxError', 'TemplateNotFound', 'Template',
            'TemplateLoader']
 
 
@@ -178,11 +177,10 @@
     The value of the `py:attrs` attribute should be a dictionary. The keys and
     values of that dictionary will be added as attributes to the element:
     
-    >>> ctxt = Context(foo={'class': 'collapse'})
     >>> tmpl = Template('''<ul xmlns:py="http://markup.edgewall.org/">
     ...   <li py:attrs="foo">Bar</li>
     ... </ul>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(foo={'class': 'collapse'})
     <ul>
       <li class="collapse">Bar</li>
     </ul>
@@ -190,8 +188,7 @@
     If the value evaluates to `None` (or any other non-truth value), no
     attributes are added:
     
-    >>> ctxt = Context(foo=None)
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(foo=None)
     <ul>
       <li>Bar</li>
     </ul>
@@ -229,11 +226,10 @@
     This directive replaces the content of the element with the result of
     evaluating the value of the `py:content` attribute:
     
-    >>> ctxt = Context(bar='Bye')
     >>> tmpl = Template('''<ul xmlns:py="http://markup.edgewall.org/">
     ...   <li py:content="bar">Hello</li>
     ... </ul>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(bar='Bye')
     <ul>
       <li>Bye</li>
     </ul>
@@ -266,14 +262,13 @@
     A named template function can be used just like a normal Python function
     from template expressions:
     
-    >>> ctxt = Context(bar='Bye')
     >>> tmpl = Template('''<div xmlns:py="http://markup.edgewall.org/">
     ...   <p py:def="echo(greeting, name='world')" class="message">
     ...     ${greeting}, ${name}!
     ...   </p>
     ...   ${echo('Hi', name='you')}
     ... </div>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(bar='Bye')
     <div>
       <p class="message">
         Hi, you!
@@ -283,14 +278,13 @@
     If a function does not require parameters, the parenthesis can be omitted
     both when defining and when calling it:
     
-    >>> ctxt = Context(bar='Bye')
     >>> tmpl = Template('''<div xmlns:py="http://markup.edgewall.org/">
     ...   <p py:def="helloworld" class="message">
     ...     Hello, world!
     ...   </p>
     ...   ${helloworld}
     ... </div>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(bar='Bye')
     <div>
       <p class="message">
         Hello, world!
@@ -343,11 +337,10 @@
     """Implementation of the `py:for` template directive for repeating an
     element based on an iterable in the context data.
     
-    >>> ctxt = Context(items=[1, 2, 3])
     >>> tmpl = Template('''<ul xmlns:py="http://markup.edgewall.org/">
     ...   <li py:for="item in items">${item}</li>
     ... </ul>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(items=[1, 2, 3])
     <ul>
       <li>1</li><li>2</li><li>3</li>
     </ul>
@@ -390,11 +383,10 @@
     """Implementation of the `py:if` template directive for conditionally
     excluding elements from being output.
     
-    >>> ctxt = Context(foo=True, bar='Hello')
     >>> tmpl = Template('''<div xmlns:py="http://markup.edgewall.org/">
     ...   <b py:if="foo">${bar}</b>
     ... </div>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(foo=True, bar='Hello')
     <div>
       <b>Hello</b>
     </div>
@@ -450,11 +442,10 @@
     This directive replaces the element with the result of evaluating the
     value of the `py:replace` attribute:
     
-    >>> ctxt = Context(bar='Bye')
     >>> tmpl = Template('''<div xmlns:py="http://markup.edgewall.org/">
     ...   <span py:replace="bar">Hello</span>
     ... </div>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(bar='Bye')
     <div>
       Bye
     </div>
@@ -462,11 +453,10 @@
     This directive is equivalent to `py:content` combined with `py:strip`,
     providing a less verbose way to achieve the same effect:
     
-    >>> ctxt = Context(bar='Bye')
     >>> tmpl = Template('''<div xmlns:py="http://markup.edgewall.org/">
     ...   <span py:content="bar" py:strip="">Hello</span>
     ... </div>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate(bar='Bye')
     <div>
       Bye
     </div>
@@ -538,14 +528,13 @@
     If no `py:when` directive is matched then the fallback directive
     `py:otherwise` will be used.
     
-    >>> ctxt = Context()
     >>> tmpl = Template('''<div xmlns:py="http://markup.edgewall.org/"
     ...   py:choose="">
     ...   <span py:when="0 == 1">0</span>
     ...   <span py:when="1 == 1">1</span>
     ...   <span py:otherwise="">2</span>
     ... </div>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate()
     <div>
       <span>1</span>
     </div>
@@ -558,7 +547,7 @@
     ...   <span py:when="1">1</span>
     ...   <span py:when="2">2</span>
     ... </div>''')
-    >>> print tmpl.generate(ctxt)
+    >>> print tmpl.generate()
     <div>
       <span>2</span>
     </div>
@@ -627,7 +616,7 @@
     >>> tmpl = Template('''<div xmlns:py="http://markup.edgewall.org/">
     ...   <span py:with="y=7; z=x+10">$x $y $z</span>
     ... </div>''')
-    >>> print tmpl.generate(Context(x=42))
+    >>> print tmpl.generate(x=42)
     <div>
       <span>42 7 52</span>
     </div>
@@ -839,16 +828,25 @@
         return _interpolate(text, [cls._FULL_EXPR_RE, cls._SHORT_EXPR_RE])
     _interpolate = classmethod(_interpolate)
 
-    def generate(self, ctxt=None):
+    def generate(self, *args, **kwargs):
         """Apply the template to the given context data.
         
-        @param ctxt: a `Context` instance containing the data for the template
+        Any keyword arguments are made available to the template as context
+        data.
+        
+        Only one positional argument is accepted: if it is provided, it must be
+        an instance of the `Context` class, and keyword arguments are ignored.
+        This calling style is used for internal processing.
+        
         @return: a markup event stream representing the result of applying
             the template to the context data.
         """
-        if ctxt is None:
-            ctxt = Context()
-        if not hasattr(ctxt, '_match_templates'):
+        if args:
+            assert len(args) == 1
+            ctxt = args[0]
+            assert isinstance(ctxt, Context)
+        else:
+            ctxt = Context(**kwargs)
             ctxt._match_templates = []
 
         stream = self.stream
--- a/markup/tests/template.py
+++ b/markup/tests/template.py
@@ -16,8 +16,7 @@
 import sys
 
 from markup.core import Markup, Stream
-from markup.template import BadDirectiveError, Context, Template, \
-                            TemplateSyntaxError
+from markup.template import BadDirectiveError, Template, TemplateSyntaxError
 
 
 class AttrsDirectiveTestCase(unittest.TestCase):
@@ -33,7 +32,7 @@
         items = [{'id': 1, 'class': 'foo'}, {'id': 2, 'class': 'bar'}]
         self.assertEqual("""<doc>
           <elem id="1" class="foo"/><elem id="2" class="bar"/>
-        </doc>""", str(tmpl.generate(Context(items=items))))
+        </doc>""", str(tmpl.generate(items=items)))
 
     def test_update_existing_attr(self):
         """
@@ -202,7 +201,7 @@
             <b>3</b>
             <b>4</b>
             <b>5</b>
-        </doc>""", str(tmpl.generate(Context(items=range(1, 6)))))
+        </doc>""", str(tmpl.generate(items=range(1, 6))))
 
     def test_as_element(self):
         """
@@ -219,7 +218,7 @@
             <b>3</b>
             <b>4</b>
             <b>5</b>
-        </doc>""", str(tmpl.generate(Context(items=range(1, 6)))))
+        </doc>""", str(tmpl.generate(items=range(1, 6))))
 
 
 class IfDirectiveTestCase(unittest.TestCase):
@@ -235,7 +234,7 @@
         </doc>""")
         self.assertEqual("""<doc>
           Hello
-        </doc>""", str(tmpl.generate(Context(foo=True, bar='Hello'))))
+        </doc>""", str(tmpl.generate(foo=True, bar='Hello')))
 
     def test_as_element(self):
         """
@@ -246,7 +245,7 @@
         </doc>""")
         self.assertEqual("""<doc>
           Hello
-        </doc>""", str(tmpl.generate(Context(foo=True, bar='Hello'))))
+        </doc>""", str(tmpl.generate(foo=True, bar='Hello')))
 
 
 class MatchDirectiveTestCase(unittest.TestCase):
@@ -427,7 +426,7 @@
           42
           84
           42
-        </div>""", str(tmpl.generate(Context(x=42))))
+        </div>""", str(tmpl.generate(x=42)))
 
     def test_as_element(self):
         tmpl = Template("""<div xmlns:py="http://markup.edgewall.org/">
@@ -435,7 +434,7 @@
         </div>""")
         self.assertEqual("""<div>
           84
-        </div>""", str(tmpl.generate(Context(x=42))))
+        </div>""", str(tmpl.generate(x=42)))
 
 
 class TemplateTestCase(unittest.TestCase):
@@ -488,9 +487,8 @@
         self.assertEqual(' baz', parts[2][1])
 
     def test_interpolate_mixed3(self):
-        ctxt = Context(var=42)
         tmpl = Template('<root> ${var} $var</root>')
-        self.assertEqual('<root> 42 42</root>', str(tmpl.generate(ctxt)))
+        self.assertEqual('<root> 42 42</root>', str(tmpl.generate(var=42)))
 
     def test_interpolate_non_string_attrs(self):
         tmpl = Template('<root attr="${1}"/>')
@@ -498,8 +496,7 @@
 
     def test_interpolate_list_result(self):
         tmpl = Template('<root>$foo</root>')
-        ctxt = Context(foo=('buzz',))
-        self.assertEqual('<root>buzz</root>', str(tmpl.generate(ctxt)))
+        self.assertEqual('<root>buzz</root>', str(tmpl.generate(foo=('buzz',))))
 
     def test_empty_attr(self):
         tmpl = Template('<root attr=""/>')
@@ -560,7 +557,7 @@
         </div>""")
         self.assertEqual("""<div>
           <b>foo</b>
-        </div>""", str(tmpl.generate(Context(myvar=Markup('<b>foo</b>')))))
+        </div>""", str(tmpl.generate(myvar=Markup('<b>foo</b>'))))
 
     def test_text_noescape_quotes(self):
         """
@@ -571,7 +568,7 @@
         </div>""")
         self.assertEqual("""<div>
           "foo"
-        </div>""", str(tmpl.generate(Context(myvar='"foo"'))))
+        </div>""", str(tmpl.generate(myvar='"foo"')))
 
     def test_attr_escape_quotes(self):
         """
@@ -582,7 +579,7 @@
         </div>""")
         self.assertEqual("""<div>
           <elem class="&#34;foo&#34;"/>
-        </div>""", str(tmpl.generate(Context(myvar='"foo"'))))
+        </div>""", str(tmpl.generate(myvar='"foo"')))
 
     def test_directive_element(self):
         tmpl = Template("""<div xmlns:py="http://markup.edgewall.org/">
@@ -590,7 +587,7 @@
         </div>""")
         self.assertEqual("""<div>
           bar
-        </div>""", str(tmpl.generate(Context(myvar='"foo"'))))
+        </div>""", str(tmpl.generate(myvar='"foo"')))
 
     def test_normal_comment(self):
         tmpl = Template("""<div xmlns:py="http://markup.edgewall.org/">
Copyright (C) 2012-2017 Edgewall Software