示例#1
0
 def test_option_tostrfunc(self):
     input = "<p>Hello #{name}!</p>"
     if "passed tostrfunc option then use it":
         globals()['my_str'] = lambda s: s.upper()
         t = tenjin.Template(None, input=input, tostrfunc='my_str')
         output = t.render({'name': 'Haruhi'})
         ok (output) == "<p>Hello HARUHI!</p>"
         ok (t.script) == self.lvars.replace('=to_str', '=my_str') + \
                          "_extend(('''<p>Hello ''', _to_str(name), '''!</p>''', ));"
         globals().pop('my_str')
         #
         t = tenjin.Template(None, input=input, tostrfunc='str')
         output = t.render({'name': None})
         ok (output) == "<p>Hello None!</p>"
         #
         t = tenjin.Template(None, input=input, tostrfunc='str.upper')
         output = t.render({'name': 'sos'})
         ok (output) == "<p>Hello SOS!</p>"
     if "passed False as tostrfunc option then no function is used":
         t = tenjin.Template(None, input=input, tostrfunc=False)
         output = t.render({'name': 'Haruhi'})
         ok (output) == "<p>Hello Haruhi!</p>"
         ok (t.script) == self.lvars.replace('=to_str', '=False') + \
                          "_extend(('''<p>Hello ''', (name), '''!</p>''', ));"
         #
         def f(): t.render({'name': 123})
         if python2:
             ok (f).raises(TypeError, 'sequence item 1: expected string, int found')
         elif python3:
             ok (f).raises(TypeError, 'sequence item 1: expected str instance, int found')
     if "passed wrong function name as tostrfunc option then raises error":
         t = tenjin.Template(None, input=input, tostrfunc='johnsmith')
         def f(): t.render({'name': 'Haruhi'})
         #ok (f).raises(TypeError, "'NoneType' object is not callable")
         ok (f).raises(NameError, _errmsg("name 'johnsmith' is not defined"))
示例#2
0
 def test_option_escapefunc(self):
     input = "<p>Hello ${name}!</p>"
     if "passed escapefunc option then use it":
         globals()['my_escape'] = lambda s: s.lower()
         t = tenjin.Template(None, input=input, escapefunc='my_escape')
         output = t.render({'name': 'Haruhi'})
         ok (output) == "<p>Hello haruhi!</p>"
         ok (t.script) == self.lvars.replace('=escape', '=my_escape') + \
                          "_extend(('''<p>Hello ''', _escape(_to_str(name)), '''!</p>''', ));"
         globals().pop('my_escape')
         #
         global cgi
         import cgi
         t = tenjin.Template(None, input=input, escapefunc='cgi.escape')
         output = t.render({'name': '&<>"'})
         ok (output) == "<p>Hello &amp;&lt;&gt;\"!</p>"
     if "passed False as escapefunc option then no function is used":
         t = tenjin.Template(None, input=input, escapefunc=False)
         output = t.render({'name': 'Haru&Kyon'})
         ok (output) == "<p>Hello Haru&Kyon!</p>"
         ok (t.script) == self.lvars.replace('=escape', '=False') + \
                          "_extend(('''<p>Hello ''', _to_str(name), '''!</p>''', ));"
     if "passed wrong function name as tostrfunc option then raises error":
         t = tenjin.Template(None, input=input, escapefunc='kyonsmith')
         def f(): t.render({'name': 'Haruhi'})
         #ok (f).raises(TypeError, "'NoneType' object is not callable")
         ok (f).raises(NameError, _errmsg("name 'kyonsmith' is not defined"))
示例#3
0
 def test_with_unicode_template_and_binary_data(self):
     t = tenjin.Template(encoding='utf-8')
     input = "**あ**\n#{'あ'}\n"
     script = lvars + u"_extend((u'''**\u3042**\n''', _to_str('\u3042'), u'''\\n''', ));\n"
     ok (t.convert(input)) == script
     ## do nothing in to_str()
     self._test_render(
         template        = t,
         to_str          = tenjin.generate_tostrfunc(encode=None, decode=None),
         expected_buf    = [u'**\u3042**\n', '\xe3\x81\x82', u'\n'],
         expected_errcls = UnicodeDecodeError,
         expected_errmsg = "'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)"
      )
     ## encode unicode in binary in to_str()
     self._test_render(
         template        = t,
         to_str          = tenjin.generate_tostrfunc(encode='utf-8', decode=None),
         expected_buf    = [u'**\u3042**\n', '\xe3\x81\x82', u'\n'],
         expected_errcls = UnicodeDecodeError,
         expected_errmsg = "'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)"
      )
     ## decode binary into unicode in to_str()
     self._test_render(
         template        = t,
         to_str          = tenjin.generate_tostrfunc(encode=None, decode='utf-8'),
         expected_buf    = [u'**\u3042**\n', u'\u3042', u'\n'],
         expected_output = u"**あ**\nあ\n"
     )
示例#4
0
    def test_filename1(self):
        input = """<ul>
<?py for i in range(0,3): ?>
<li>#{i}</li>
<?py #endfor ?>
</ul>
"""
        filename = 'test_filename1.tenjin'
        try:
            write_file(filename, input)
            template1 = tenjin.Template(filename)
            template2 = tenjin.Template()
            ok (template2.convert(input)) == template1.script
            ok (template2.render()) == template1.render()
        finally:
            try:
                os.remove(filename)
            except:
                pass
示例#5
0
 def test_trace(self):
     if "trace is on then prints template filename as HTML comments":
         filename = "test.trace.pyhtml"
         input = "<p>hello #{name}!</p>\n"
         expected = ( "<!-- ***** begin: %s ***** -->\n"
                      "<p>hello world!</p>\n"
                      "<!-- ***** end: %s ***** -->\n" ) % (filename, filename)
         t = tenjin.Template(filename, input=input, trace=True)
         output = t.render({'name':'world'})
         ok (output) == expected
示例#6
0
 def test_add_template(self):
     if "template is added then it can be got by get_template()":
         input = """val=#{val}"""
         template = tenjin.Template('foo.pyhtml', input=input)
         engine = tenjin.Engine(postfix='.pyhtml')
         engine.add_template(template)
         ok (engine.get_template('foo.pyhtml')) == template
         ok (engine.get_template(':foo')) == template
     if "template is added then it should not create cache file":
         ok (engine.render(':foo', {'val': 'ABC'})) == 'val=ABC'
         not_ok ('foo.pyhtml').exists()
示例#7
0
    def _(self):
        input = """
<p>${f({'a':1})+g({'b':2})}</p>
<p>#{f({'c':3})+g({'d':4})}</p>
"""
        expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''
<p>''', _escape(_to_str(f({'a':1})+g({'b':2}))), '''</p>
<p>''', _to_str(f({'c':3})+g({'d':4})), '''</p>\n''', ));
"""
        t = tenjin.Template()
        script = t.convert(input)
        ok (script) == expected
示例#8
0
 def test_get_template(self):
     e1 = tenjin.Engine(path=['_views/blog', '_views'], postfix='.pyhtml')
     filepath  = '_views/blog/index.pyhtml'
     fullpath  = os.getcwd() + filepath
     cachepath = fullpath + '.cache'
     assert not os.path.exists(cachepath)
     t = None
     if spec("return template object.") and \
        spec("accept template_name such as ':index'."):
         t = e1.get_template(':index')
         ok (t).is_a(tenjin.Template)
         ok (t.filename) == filepath
     if spec("if template object is added by add_template(), return it."):
         tmp = tenjin.Template('foo.pyhtml', input="<<dummy>>")
         e1.add_template(tmp)
         ok (e1.get_template('foo.pyhtml')).is_(tmp)
     if spec("get filepath and fullpath of template"):
         e1._filepaths['index.pyhtml'] == (filepath, fullpath)
     if spec("if template file is not found then raise TemplateNotFoundError"):
         def f(): e1.get_template('index')
         ok (f).raises(tenjin.TemplateNotFoundError, "index: filename not found (path=['_views/blog', '_views']).")
     if spec("use full path as base of cache file path") and \
        spec("get template object from cache"):
         ok (list(e1.cache.items.keys())) == ["%s/_views/blog/index.pyhtml.cache" % os.getcwd()]
     if spec("change template filename according to prefer_fullpath"):
         pass
     if spec("use full path as base of cache file path"):
         pass
     if spec("get template object from cache"):
         pass
     if spec("if template object is not found in cache or is expired..."):
         e1.cache.clear()
         ok (len(e1.cache.items)) == 0
         tname = ':layout'
         fpath = '_views/layout.pyhtml'
         cpath = os.path.join(os.getcwd(), '_views/layout.pyhtml.cache')
         not_ok (cpath).exists()
         if spec("create template object."):
             t = e1.get_template(tname)
             ok (t).is_a(tenjin.Template)
         if spec("set timestamp and filename of template object."):
             ok (t.timestamp) == os.path.getmtime(filepath)
             ok (t.filename) == fpath
             delta = JYTHON and 0.03 or 0.003
             ok (t._last_checked_at).in_delta(time.time(), delta)
         if spec("save template object into cache."):
             ok (cpath).exists()
             ok (len(e1.cache.items)) == 1
             ok (e1.cache.items).contains(cpath)
示例#9
0
    def test_new_notation(self):
        input = r"""
a=${a}
b=#{b}
c={=c=}
d={==d==}
"""
        expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''
a=''', _escape(_to_str(a)), '''
b=''', _to_str(b), '''
c=''', _escape(_to_str(c)), '''
d=''', _to_str(d), '''\n''', ));
"""
        t = tenjin.Template()
        ok (t.convert(input)) == expected
示例#10
0
 def test_import_module1(self):
     import base64
     if python2:
         input = "#{base64.encodestring('tenjin')}"
     elif python3:
         if hasattr(base64, 'encodebytes'):             # python 3.1 or later
             input = "#{base64.encodebytes(b'tenjin')}"
         else:                                          # python 3.0
             input = "#{base64.encodestring(b'tenjin')}"
     template = tenjin.Template()
     template.convert(input)
     def f1():
         template.render()
     ok (f1).raises(NameError)
     #tenjin.import_module('base64')
     globals()['base64'] = base64
     #ok (f1).not_raise()
     f1()
示例#11
0
 def test_import_module2(self):
     if python2:
         import rfc822
         input = "#{rfc822.formatdate()}"
     elif python3:
         import email.utils
         input = "#{email.utils.formatdate()}"
     template = tenjin.Template()
     template.convert(input)
     def f1():
         template.render()
     ok (f1).raises(NameError)
     if python2:
         #tenjin.import_module(rfc822)
         globals()['rfc822'] = rfc822
     elif python3:
         globals()['email'] = email
     #ok (f1).not_raise()
     f1()
示例#12
0
    def test_input(self):
        input = r"""<!DOCTYPE>
<ul>
<?py for item in items: ?>
  <li>#{item}</li>
<?py #endfor ?>
</ul>
"""
        script = self.lvars + r"""_extend(('''<!DOCTYPE>
<ul>\n''', ));
for item in items:
    _extend(('''  <li>''', _to_str(item), '''</li>\n''', ));
#endfor
_extend(('''</ul>\n''', ));
"""
        t = tenjin.Template("test.foobar.pyhtml", input=input)
        if "input argument is specified then regard it as template content":
            ok (t.script) == script
        if "input argument is specified then timestamp is set to False":
            ok (t.timestamp) == False
示例#13
0
 def test__get_template_from_cache(self):
     e1 = tenjin.Engine(path=['_views/blog', '_views'], postfix='.pyhtml')
     fpath = '_views/blog/index.pyhtml'
     cpath = fpath + '.cache'
     if spec("if template not found in cache, return None"):
         ret = e1._get_template_from_cache(cpath, fpath)
         ok (ret) == None
     t = tenjin.Template(fpath)
     e1.cache.set(fpath + '.cache', t)
     if spec("if checked within a sec, skip timestamp check."):
         #try:
         #    t.timestamp = time.time() - 0.2
         #    #import pdb; pdb.set_trace()
         #    tenjin.logger = DebugLogger()
         #    ret = e1._get_template_from_cache(cpath, fpath)
         #    msg = tenjin.logger.messages[0]
         #    ok (msg.startswith("[TRACE] [tenjin.Engine] timestamp check skipped (")) == True
         #finally:
         #    tenjin.logger = None
         pass
     if spec("if timestamp of template objectis same as file, return it."):
         t._last_checked_at = None
         t.timestamp = os.path.getmtime(fpath)
         ok (e1._get_template_from_cache(cpath, fpath)).is_(t)
         delta = JYTHON and 0.03 or 0.001
         ok (t._last_checked_at).in_delta(time.time(), delta)
     if spec("if timestamp of template object is different from file, clear it"):
         t.timestamp = t.timestamp + 1
         t._last_checked_at = None
         try:
             #import pdb; pdb.set_trace()
             tenjin.logger = DebugLogger()
             ret = e1._get_template_from_cache(cpath, fpath)
             msg = tenjin.logger.messages[0]
             ok (msg) == "[INFO] [tenjin.Engine] cache expired (filepath='_views/blog/index.pyhtml')"
         finally:
             tenjin.logger = None
示例#14
0
def get_tenjin_tests():
    if not tenjin:
        return []

    try:
        import webext
        helpers = {'to_str': webext.to_str, 'escape': webext.escape_html}
    except ImportError:
        helpers = {
            'to_str': tenjin.helpers.to_str,
            'escape': tenjin.helpers.escape
        }
    tenjin_template = tenjin.Template(encoding='utf8')
    tenjin_template.convert("""\
<table>
    <?py for row in table: ?>
    <tr>
        <?py for key, value in row.items(): ?>
        <td>${ key }</td><td>#{ value }</td>
        <?py #end ?>
    </tr>
    <?py #end ?>
</table>
""")

    ctx = {
        'table': TABLE_DATA,
    }

    def test_tenjin():
        """tenjin template"""
        return tenjin_template.render(ctx, helpers)

    return [
        test_tenjin,
    ]
示例#15
0
# region: tenjin

try:
    import tenjin
except ImportError:
    test_tenjin = None
else:
    try:
        import webext
        helpers = {'to_str': webext.to_str, 'escape': webext.escape_html}
    except ImportError:
        helpers = {
            'to_str': tenjin.helpers.to_str,
            'escape': tenjin.helpers.escape
        }
    tenjin_template = tenjin.Template(encoding='utf8')
    tenjin_template.convert(
        s("""\
<table>
    <?py for row in table: ?>
    <tr>
        <?py for key, value in row.items(): ?>
        <td>${ key }</td><td>#{ value }</td>
        <?py #end ?>
    </tr>
    <?py #end ?>
</table>
"""))

    def test_tenjin():
        return tenjin_template.render(ctx, helpers)
示例#16
0
      #end for
      </table>
    </div>
  </body>
</html>\
""", searchList=[dict(context)])

    def test_cheetah():
        unicode(cheetah_template)

try:
    import tenjin
except ImportError:
    test_tenjin = None
else:
    tenjin_template = tenjin.Template()
    tenjin_template.convert("""\
<!doctype html>
<html>
  <head>
    <title>${page_title}</title>
  </head>
  <body>
    <div class="header">
      <h1>${page_title}</h1>
    </div>
    <ul class="navigation">
<?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]: ?>
      <li><a href="${href}">${caption}</a></li>
<?py #end ?>
    </ul>
示例#17
0
import tenjin
template = tenjin.Template('views/page.pyhtml')
print(template.script)

### or:
#template = tenjin.Template()
#with open('views/page.pyhtml') as f:
#    print(template.convert(f.read(), 'views/page.pyhtml'))

### or:
#engine = tenjin.Engine(path=['views'])
#print(engine.get_template('page.pyhtml').script)
示例#18
0
def _makemessages(domain, locale, localedir, extensions):
    sys.stdout.write("processing language %s\n" % locale)

    basedir = os.path.join(localedir, locale, 'LC_MESSAGES')
    if not os.path.isdir(basedir):
        os.makedirs(basedir)

    pofile = '%s/%s.po' % (basedir, domain)
    potfile = '%s/%s.pot' % (basedir, domain)
    if os.path.exists(potfile):
        os.unlink(potfile)

    for ff_name in find_files(domain):
        dirpath, f_name = os.path.split(ff_name)
        file_base, file_ext = os.path.splitext(f_name)

        if domain == 'front' \
                and (file_ext == '.py' or file_ext in extensions):
            thefile = f_name
            if file_ext in extensions:
                thefile = '%s.py' % f_name
                import tenjin
                src = tenjin.Template(ff_name).script
                with open(os.path.join(dirpath, thefile), "w") as f:
                    f.write(src)
        else:
            continue

        cmd = ('xgettext -d %s -L Python --keyword=gettext_noop '
               '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 '
               '--keyword=ugettext_noop --keyword=ugettext_lazy '
               '--keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 '
               '--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 '
               '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 '
               '--add-comments=Translators -o - "%s"' %
               (domain, os.path.join(dirpath, thefile)))
        msgs, errors = _popen(cmd)
        if errors:
            if thefile != f_name:
                os.unlink(os.path.join(dirpath, thefile))
            if os.path.exists(potfile):
                os.unlink(potfile)
            raise CommandError(
                "errors happened while running xgettext on %s\n%s" %
                (f_name, errors))
        if msgs:
            if thefile != f_name:
                old = '#: ' + os.path.join(dirpath, thefile)
                new = '#: ' + ff_name
                msgs = msgs.replace(old, new)
            if os.path.exists(potfile):
                # Strip the header
                msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
            else:
                msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
            with open(potfile, 'ab') as f:
                f.write(msgs)
        if thefile != f_name:
            os.unlink(os.path.join(dirpath, thefile))

    if os.path.exists(potfile):
        msgs, errors = _popen('msguniq --to-code=utf-8 "%s"' % potfile)
        if errors:
            os.unlink(potfile)
            raise CommandError("errors happened while running msguniq\n%s" %
                               errors)

        if os.path.exists(pofile):
            with open(potfile, 'w') as f:
                f.write(msgs)
            msgs, errors = _popen('msgmerge -q "%s" "%s"' % (pofile, potfile))
            if errors:
                os.unlink(potfile)
                raise CommandError(
                    "errors happened while running msgmerge\n%s" % errors)

        with open(pofile, 'wb') as f:
            f.write(msgs)
        os.unlink(potfile)
示例#19
0
try:
    import tenjin
except ImportError:
    test(name="tenjin")
else:
    try:
        import webext

        helpers = {"to_str": webext.to_str, "escape": webext.escape_html}
    except ImportError:
        helpers = {
            "to_str": tenjin.helpers.to_str,
            "escape": tenjin.helpers.escape,
        }
    tenjin_template = tenjin.Template(encoding="utf8")
    tenjin_template.convert(
        s("""\
<table>
    <?py for row in table: ?>
    <tr>
        <?py for key, value in row.items(): ?>
        <td>${ key }</td><td>#{ value }</td>
        <?py #end ?>
    </tr>
    <?py #end ?>
</table>
"""))

    @test(40)
    def test_tenjin() -> str:
示例#20
0
    def test_add_expr(self):
        input = r"""
not escape: #{var}
escape: ${var}
"""
        if spec("nothing is specified then both _to_str() and _escape() are used."):
            t = tenjin.Template()
            script = t.convert(input)
            expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''
not escape: ''', _to_str(var), '''
escape: ''', _escape(_to_str(var)), '''\n''', ));
"""
            ok (script) == expected
        if spec("when tostrfunc is False then skips _to_str()."):
            expected = r"""_extend=_buf.extend;_to_str=False;_escape=escape; _extend(('''
not escape: ''', (var), '''
escape: ''', _escape(var), '''\n''', ));
"""
            t = tenjin.Template(tostrfunc=False)
            ok (t.convert(input)) == expected
        if spec("escapefunc is False then skips _escape()."):
            expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=False; _extend(('''
not escape: ''', _to_str(var), '''
escape: ''', _to_str(var), '''\n''', ));
"""
            t = tenjin.Template(escapefunc=False)
            ok (t.convert(input)) == expected
        if spec("both tostr and escapefunc are False then skips _to_str() and _escape()."):
            expected = r"""_extend=_buf.extend;_to_str=False;_escape=False; _extend(('''
not escape: ''', (var), '''
escape: ''', (var), '''\n''', ));
"""
            t = tenjin.Template(tostrfunc=False, escapefunc=False)
            ok (t.convert(input)) == expected
        if spec("get_expr_and_flags() returns flag_tostr=False then ignores _escape()."):
            tr = Tracer()
            def fn(orig, *args):
                expr, (flag_escape, flag_tostr) = orig(*args)
                return expr, (flag_escape, False)
            expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''
not escape: ''', (var), '''
escape: ''', _escape(var), '''\n''', ));
"""
            t = tenjin.Template()
            tr.fake_method(t, get_expr_and_flags=fn)
            ok (t.convert(input)) == expected
        if spec("get_expr_and_flags() returns flag_escape=False then ignores _escape()."):
            tr = Tracer()
            def fn(orig, *args):
                expr, (flag_escape, flag_tostr) = orig(*args)
                return expr, (False, flag_tostr)
            expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''
not escape: ''', _to_str(var), '''
escape: ''', _to_str(var), '''\n''', ));
"""
            t = tenjin.Template()
            tr.fake_method(t, get_expr_and_flags=fn)
            ok (t.convert(input)) == expected
        if spec("get_expr_and_flags() returns both flags False then ignores both _to_str() and _escape()."):
            tr = Tracer()
            def fn(orig, *args):
                expr, (flag_escape, flag_tostr) = orig(*args)
                return expr, (False, False)
            expected = r"""_extend=_buf.extend;_to_str=to_str;_escape=escape; _extend(('''
not escape: ''', (var), '''
escape: ''', (var), '''\n''', ));
"""
            t = tenjin.Template()
            tr.fake_method(t, get_expr_and_flags=fn)
            ok (t.convert(input)) == expected
示例#21
0
 def f():
     input = "<?py #@ARGS 1x ?>"
     template = tenjin.Template()
     template.convert(input)
示例#22
0
 def _convert(input):
     return tenjin.Template(input=input).script
示例#23
0
 def _test(self):
     input     = getattr(self, 'input', None)
     source    = getattr(self, 'source', None)
     expected  = getattr(self, 'expected', None)
     exception = getattr(self, 'exception', None)
     errormsg  = getattr(self, 'errormsg', None)
     options   = getattr(self, 'options', {})
     filename  = getattr(self, 'filename', None)
     context   = getattr(self, 'context', {})
     testopts  = getattr(self, 'testopts', None)
     disabled  = getattr(self, 'disabled', None)
     templateclass = getattr(self, 'templateclass', None)
     encoding  = None
     #
     if disabled:
         return
     #
     if testopts:
         if 'crchar' in testopts:
             ch = testopts['crchar']
             if input:     input    = input.replace(ch, "\r")
             if source:    source   = source.replace(ch, "\r")
             if expected:  expected = expected.replace(ch, "\r")
         if testopts.get('escapefunc') == 'cgi.escape':
             #import cgi
             #context['escape'] = cgi.escape
             pass
         if testopts.get('tostrfunc') == 'str':
             #context['to_str'] = str
             pass
         if 'encoding' in testopts:
             encoding = testopts.get('encoding')
         if 'templateclass' in testopts:
             templateclass = testopts.get('templateclass')
     #
     if python3:
         input  = input.replace('urllib.quote', 'urllib.parse.quote')
         source = source.replace('urllib.quote', 'urllib.parse.quote')
         if encoding:
             if source:
                 source = source.replace("u'''", "'''").replace("u'", "'")
                 input  = input.replace("u'", "'")
     #
     if JYTHON:
         if self._testMethodName == 'test_syntaxerr1':
             errormsg = r"mismatched input '\n' expecting COLON"
     #
     if PYPY:
         if errormsg:
             errormsg = _errmsg(errormsg)
     #
     if exception:
         try:
             template = tenjin.Template(**options)
             template.convert(input, filename)
             template.render(context)
             self.fail('%s is expected but not raised.' % exception)
         except Exception:
             ex = sys.exc_info()[1]
             ok (ex.__class__) == exception
             #ok (ex).is_a(exception)
             if errormsg:
                 ## SyntaxError has 'msg' attribute instead of 'message'. Why?
                 #ok (ex.message or ex.msg) == errormsg # failed in python2.3
                 ok (ex.args[0]) == errormsg
             if filename:
                 ok (ex.filename) == filename
     else:
         if templateclass:
             templateclass = eval(templateclass)
             template = templateclass(**options)
         else:
             template = tenjin.Template(**options)
         script = template.convert(input, filename)
         ok (script) == source         # encoding=encoding
         if expected:
             output = template.render(context)
             ok (output) == expected   # encoding=encoding