File: //usr/lib/python3/dist-packages/genshi/template/tests/directives.py
# -*- coding: utf-8 -*-
#
# Copyright (C) 2006-2010 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://genshi.edgewall.org/wiki/License.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://genshi.edgewall.org/log/.
import doctest
import re
import sys
import unittest
from genshi.compat import IS_PYTHON2
from genshi.template import directives, MarkupTemplate, TextTemplate, \
TemplateRuntimeError, TemplateSyntaxError
class AttrsDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:attrs` template directive."""
def test_combined_with_loop(self):
"""
Verify that the directive has access to the loop variables.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<elem py:for="item in items" py:attrs="item"/>
</doc>""")
items = [{'id': 1}, {'id': 2}]
self.assertEqual("""<doc>
<elem id="1"/><elem id="2"/>
</doc>""", tmpl.generate(items=items).render(encoding=None))
def test_update_existing_attr(self):
"""
Verify that an attribute value that evaluates to `None` removes an
existing attribute of that name.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<elem class="foo" py:attrs="{'class': 'bar'}"/>
</doc>""")
self.assertEqual("""<doc>
<elem class="bar"/>
</doc>""", tmpl.generate().render(encoding=None))
def test_remove_existing_attr(self):
"""
Verify that an attribute value that evaluates to `None` removes an
existing attribute of that name.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<elem class="foo" py:attrs="{'class': None}"/>
</doc>""")
self.assertEqual("""<doc>
<elem/>
</doc>""", tmpl.generate().render(encoding=None))
class ChooseDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:choose` template directive and the complementary
directives `py:when` and `py:otherwise`."""
def test_multiple_true_whens(self):
"""
Verify that, if multiple `py:when` bodies match, only the first is
output.
"""
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/" py:choose="">
<span py:when="1 == 1">1</span>
<span py:when="2 == 2">2</span>
<span py:when="3 == 3">3</span>
</div>""")
self.assertEqual("""<div>
<span>1</span>
</div>""", tmpl.generate().render(encoding=None))
def test_otherwise(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/" py:choose="">
<span py:when="False">hidden</span>
<span py:otherwise="">hello</span>
</div>""")
self.assertEqual("""<div>
<span>hello</span>
</div>""", tmpl.generate().render(encoding=None))
def test_nesting(self):
"""
Verify that `py:choose` blocks can be nested:
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:choose="1">
<div py:when="1" py:choose="3">
<span py:when="2">2</span>
<span py:when="3">3</span>
</div>
</div>
</doc>""")
self.assertEqual("""<doc>
<div>
<div>
<span>3</span>
</div>
</div>
</doc>""", tmpl.generate().render(encoding=None))
def test_complex_nesting(self):
"""
Verify more complex nesting.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:choose="1">
<div py:when="1" py:choose="">
<span py:when="2">OK</span>
<span py:when="1">FAIL</span>
</div>
</div>
</doc>""")
self.assertEqual("""<doc>
<div>
<div>
<span>OK</span>
</div>
</div>
</doc>""", tmpl.generate().render(encoding=None))
def test_complex_nesting_otherwise(self):
"""
Verify more complex nesting using otherwise.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:choose="1">
<div py:when="1" py:choose="2">
<span py:when="1">FAIL</span>
<span py:otherwise="">OK</span>
</div>
</div>
</doc>""")
self.assertEqual("""<doc>
<div>
<div>
<span>OK</span>
</div>
</div>
</doc>""", tmpl.generate().render(encoding=None))
def test_when_with_strip(self):
"""
Verify that a when directive with a strip directive actually strips of
the outer element.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:choose="" py:strip="">
<span py:otherwise="">foo</span>
</div>
</doc>""")
self.assertEqual("""<doc>
<span>foo</span>
</doc>""", tmpl.generate().render(encoding=None))
def test_when_outside_choose(self):
"""
Verify that a `when` directive outside of a `choose` directive is
reported as an error.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:when="xy" />
</doc>""")
self.assertRaises(TemplateRuntimeError, str, tmpl.generate())
def test_otherwise_outside_choose(self):
"""
Verify that an `otherwise` directive outside of a `choose` directive is
reported as an error.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:otherwise="" />
</doc>""")
self.assertRaises(TemplateRuntimeError, str, tmpl.generate())
def test_when_without_test(self):
"""
Verify that an `when` directive that doesn't have a `test` attribute
is reported as an error.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:choose="" py:strip="">
<py:when>foo</py:when>
</div>
</doc>""")
self.assertRaises(TemplateRuntimeError, str, tmpl.generate())
def test_when_without_test_but_with_choose_value(self):
"""
Verify that an `when` directive that doesn't have a `test` attribute
works as expected as long as the parent `choose` directive has a test
expression.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:choose="foo" py:strip="">
<py:when>foo</py:when>
</div>
</doc>""")
self.assertEqual("""<doc>
foo
</doc>""", tmpl.generate(foo='Yeah').render(encoding=None))
def test_otherwise_without_test(self):
"""
Verify that an `otherwise` directive can be used without a `test`
attribute.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:choose="" py:strip="">
<py:otherwise>foo</py:otherwise>
</div>
</doc>""")
self.assertEqual("""<doc>
foo
</doc>""", tmpl.generate().render(encoding=None))
def test_as_element(self):
"""
Verify that the directive can also be used as an element.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:choose>
<py:when test="1 == 1">1</py:when>
<py:when test="2 == 2">2</py:when>
<py:when test="3 == 3">3</py:when>
</py:choose>
</doc>""")
self.assertEqual("""<doc>
1
</doc>""", tmpl.generate().render(encoding=None))
def test_in_text_template(self):
"""
Verify that the directive works as expected in a text template.
"""
tmpl = TextTemplate("""#choose
#when 1 == 1
1
#end
#when 2 == 2
2
#end
#when 3 == 3
3
#end
#end""")
self.assertEqual(""" 1\n""",
tmpl.generate().render(encoding=None))
class DefDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:def` template directive."""
def test_function_with_strip(self):
"""
Verify that a named template function with a strip directive actually
strips of the outer element.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:def="echo(what)" py:strip="">
<b>${what}</b>
</div>
${echo('foo')}
</doc>""")
self.assertEqual("""<doc>
<b>foo</b>
</doc>""", tmpl.generate().render(encoding=None))
def test_exec_in_replace(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<p py:def="echo(greeting, name='world')" class="message">
${greeting}, ${name}!
</p>
<div py:replace="echo('hello')"></div>
</div>""")
self.assertEqual("""<div>
<p class="message">
hello, world!
</p>
</div>""", tmpl.generate().render(encoding=None))
def test_as_element(self):
"""
Verify that the directive can also be used as an element.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:def function="echo(what)">
<b>${what}</b>
</py:def>
${echo('foo')}
</doc>""")
self.assertEqual("""<doc>
<b>foo</b>
</doc>""", tmpl.generate().render(encoding=None))
def test_nested_defs(self):
"""
Verify that a template function defined inside a conditional block can
be called from outside that block.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:if test="semantic">
<strong py:def="echo(what)">${what}</strong>
</py:if>
<py:if test="not semantic">
<b py:def="echo(what)">${what}</b>
</py:if>
${echo('foo')}
</doc>""")
self.assertEqual("""<doc>
<strong>foo</strong>
</doc>""", tmpl.generate(semantic=True).render(encoding=None))
def test_function_with_default_arg(self):
"""
Verify that keyword arguments work with `py:def` directives.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<b py:def="echo(what, bold=False)" py:strip="not bold">${what}</b>
${echo('foo')}
</doc>""")
self.assertEqual("""<doc>
foo
</doc>""", tmpl.generate().render(encoding=None))
def test_invocation_in_attribute(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:def function="echo(what)">${what or 'something'}</py:def>
<p class="${echo('foo')}">bar</p>
</doc>""")
self.assertEqual("""<doc>
<p class="foo">bar</p>
</doc>""", tmpl.generate().render(encoding=None))
def test_invocation_in_attribute_none(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:def function="echo()">${None}</py:def>
<p class="${echo()}">bar</p>
</doc>""")
self.assertEqual("""<doc>
<p>bar</p>
</doc>""", tmpl.generate().render(encoding=None))
def test_function_raising_typeerror(self):
def badfunc():
raise TypeError
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<div py:def="dobadfunc()">
${badfunc()}
</div>
<div py:content="dobadfunc()"/>
</html>""")
self.assertRaises(TypeError, list, tmpl.generate(badfunc=badfunc))
def test_def_in_matched(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<head py:match="head">${select('*')}</head>
<head>
<py:def function="maketitle(test)"><b py:replace="test" /></py:def>
<title>${maketitle(True)}</title>
</head>
</doc>""")
self.assertEqual("""<doc>
<head><title>True</title></head>
</doc>""", tmpl.generate().render(encoding=None))
def test_in_text_template(self):
"""
Verify that the directive works as expected in a text template.
"""
tmpl = TextTemplate("""
#def echo(greeting, name='world')
${greeting}, ${name}!
#end
${echo('Hi', name='you')}
""")
self.assertEqual("""
Hi, you!
""", tmpl.generate().render(encoding=None))
def test_function_with_star_args(self):
"""
Verify that a named template function using "star arguments" works as
expected.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:def="f(*args, **kwargs)">
${repr(args)}
${repr(sorted(kwargs.items()))}
</div>
${f(1, 2, a=3, b=4)}
</doc>""")
self.assertEqual("""<doc>
<div>
[1, 2]
[('a', 3), ('b', 4)]
</div>
</doc>""", tmpl.generate().render(encoding=None))
class ForDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:for` template directive."""
def test_loop_with_strip(self):
"""
Verify that the combining the `py:for` directive with `py:strip` works
correctly.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:for="item in items" py:strip="">
<b>${item}</b>
</div>
</doc>""")
self.assertEqual("""<doc>
<b>1</b>
<b>2</b>
<b>3</b>
<b>4</b>
<b>5</b>
</doc>""", tmpl.generate(items=range(1, 6)).render(encoding=None))
def test_as_element(self):
"""
Verify that the directive can also be used as an element.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:for each="item in items">
<b>${item}</b>
</py:for>
</doc>""")
self.assertEqual("""<doc>
<b>1</b>
<b>2</b>
<b>3</b>
<b>4</b>
<b>5</b>
</doc>""", tmpl.generate(items=range(1, 6)).render(encoding=None))
def test_multi_assignment(self):
"""
Verify that assignment to tuples works correctly.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:for each="k, v in items">
<p>key=$k, value=$v</p>
</py:for>
</doc>""")
self.assertEqual("""<doc>
<p>key=a, value=1</p>
<p>key=b, value=2</p>
</doc>""", tmpl.generate(items=(('a', 1), ('b', 2)))
.render(encoding=None))
def test_nested_assignment(self):
"""
Verify that assignment to nested tuples works correctly.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:for each="idx, (k, v) in items">
<p>$idx: key=$k, value=$v</p>
</py:for>
</doc>""")
self.assertEqual("""<doc>
<p>0: key=a, value=1</p>
<p>1: key=b, value=2</p>
</doc>""", tmpl.generate(items=enumerate([('a', 1), ('b', 2)]))
.render(encoding=None))
def test_not_iterable(self):
"""
Verify that assignment to nested tuples works correctly.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:for each="item in foo">
$item
</py:for>
</doc>""", filename='test.html')
try:
list(tmpl.generate(foo=12))
self.fail('Expected TemplateRuntimeError')
except TypeError as e:
assert (str(e) == "iteration over non-sequence" or
str(e) == "'int' object is not iterable")
exc_type, exc_value, exc_traceback = sys.exc_info()
frame = exc_traceback.tb_next
frames = []
while frame.tb_next:
frame = frame.tb_next
frames.append(frame)
expected_iter_str = "u'iter(foo)'" if IS_PYTHON2 else "'iter(foo)'"
self.assertEqual("<Expression %s>" % expected_iter_str,
frames[-1].tb_frame.f_code.co_name)
self.assertEqual('test.html',
frames[-1].tb_frame.f_code.co_filename)
self.assertEqual(2, frames[-1].tb_lineno)
def test_for_with_empty_value(self):
"""
Verify an empty 'for' value is an error
"""
try:
MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:for each="">
empty
</py:for>
</doc>""", filename='test.html').generate()
self.fail('ExpectedTemplateSyntaxError')
except TemplateSyntaxError as e:
self.assertEqual('test.html', e.filename)
if sys.version_info[:2] > (2,4):
self.assertEqual(2, e.lineno)
class IfDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:if` template directive."""
def test_loop_with_strip(self):
"""
Verify that the combining the `py:if` directive with `py:strip` works
correctly.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<b py:if="foo" py:strip="">${bar}</b>
</doc>""")
self.assertEqual("""<doc>
Hello
</doc>""", tmpl.generate(foo=True, bar='Hello').render(encoding=None))
def test_as_element(self):
"""
Verify that the directive can also be used as an element.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:if test="foo">${bar}</py:if>
</doc>""")
self.assertEqual("""<doc>
Hello
</doc>""", tmpl.generate(foo=True, bar='Hello').render(encoding=None))
class MatchDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:match` template directive."""
def test_with_strip(self):
"""
Verify that a match template can produce the same kind of element that
it matched without entering an infinite recursion.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<elem py:match="elem" py:strip="">
<div class="elem">${select('text()')}</div>
</elem>
<elem>Hey Joe</elem>
</doc>""")
self.assertEqual("""<doc>
<div class="elem">Hey Joe</div>
</doc>""", tmpl.generate().render(encoding=None))
def test_without_strip(self):
"""
Verify that a match template can produce the same kind of element that
it matched without entering an infinite recursion.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<elem py:match="elem">
<div class="elem">${select('text()')}</div>
</elem>
<elem>Hey Joe</elem>
</doc>""")
self.assertEqual("""<doc>
<elem>
<div class="elem">Hey Joe</div>
</elem>
</doc>""", tmpl.generate().render(encoding=None))
def test_as_element(self):
"""
Verify that the directive can also be used as an element.
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:match path="elem">
<div class="elem">${select('text()')}</div>
</py:match>
<elem>Hey Joe</elem>
</doc>""")
self.assertEqual("""<doc>
<div class="elem">Hey Joe</div>
</doc>""", tmpl.generate().render(encoding=None))
def test_recursive_match_1(self):
"""
Match directives are applied recursively, meaning that they are also
applied to any content they may have produced themselves:
"""
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<elem py:match="elem">
<div class="elem">
${select('*')}
</div>
</elem>
<elem>
<subelem>
<elem/>
</subelem>
</elem>
</doc>""")
self.assertEqual("""<doc>
<elem>
<div class="elem">
<subelem>
<elem>
<div class="elem">
</div>
</elem>
</subelem>
</div>
</elem>
</doc>""", tmpl.generate().render(encoding=None))
def test_recursive_match_2(self):
"""
When two or more match templates match the same element and also
themselves output the element they match, avoiding recursion is even
more complex, but should work.
"""
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<body py:match="body">
<div id="header"/>
${select('*')}
</body>
<body py:match="body">
${select('*')}
<div id="footer"/>
</body>
<body>
<h1>Foo</h1>
</body>
</html>""")
self.assertEqual("""<html>
<body>
<div id="header"/><h1>Foo</h1>
<div id="footer"/>
</body>
</html>""", tmpl.generate().render(encoding=None))
def test_recursive_match_3(self):
tmpl = MarkupTemplate("""<test xmlns:py="http://genshi.edgewall.org/">
<py:match path="b[@type='bullet']">
<bullet>${select('*|text()')}</bullet>
</py:match>
<py:match path="group[@type='bullet']">
<ul>${select('*')}</ul>
</py:match>
<py:match path="b">
<generic>${select('*|text()')}</generic>
</py:match>
<b>
<group type="bullet">
<b type="bullet">1</b>
<b type="bullet">2</b>
</group>
</b>
</test>
""")
self.assertEqual("""<test>
<generic>
<ul><bullet>1</bullet><bullet>2</bullet></ul>
</generic>
</test>""", tmpl.generate().render(encoding=None))
def test_not_match_self(self):
"""
See http://genshi.edgewall.org/ticket/77
"""
tmpl = MarkupTemplate("""<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<body py:match="body" py:content="select('*')" />
<h1 py:match="h1">
${select('text()')}
Goodbye!
</h1>
<body>
<h1>Hello!</h1>
</body>
</html>""")
self.assertEqual("""<html xmlns="http://www.w3.org/1999/xhtml">
<body><h1>
Hello!
Goodbye!
</h1></body>
</html>""", tmpl.generate().render(encoding=None))
def test_select_text_in_element(self):
"""
See http://genshi.edgewall.org/ticket/77#comment:1
"""
tmpl = MarkupTemplate("""<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<body py:match="body" py:content="select('*')" />
<h1 py:match="h1">
<text>
${select('text()')}
</text>
Goodbye!
</h1>
<body>
<h1>Hello!</h1>
</body>
</html>""")
self.assertEqual("""<html xmlns="http://www.w3.org/1999/xhtml">
<body><h1>
<text>
Hello!
</text>
Goodbye!
</h1></body>
</html>""", tmpl.generate().render(encoding=None))
def test_select_all_attrs(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:match="elem" py:attrs="select('@*')">
${select('text()')}
</div>
<elem id="joe">Hey Joe</elem>
</doc>""")
self.assertEqual("""<doc>
<div id="joe">
Hey Joe
</div>
</doc>""", tmpl.generate().render(encoding=None))
def test_select_all_attrs_empty(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:match="elem" py:attrs="select('@*')">
${select('text()')}
</div>
<elem>Hey Joe</elem>
</doc>""")
self.assertEqual("""<doc>
<div>
Hey Joe
</div>
</doc>""", tmpl.generate().render(encoding=None))
def test_select_all_attrs_in_body(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:match="elem">
Hey ${select('text()')} ${select('@*')}
</div>
<elem title="Cool">Joe</elem>
</doc>""")
self.assertEqual("""<doc>
<div>
Hey Joe Cool
</div>
</doc>""", tmpl.generate().render(encoding=None))
def test_def_in_match(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:def function="maketitle(test)"><b py:replace="test" /></py:def>
<head py:match="head">${select('*')}</head>
<head><title>${maketitle(True)}</title></head>
</doc>""")
self.assertEqual("""<doc>
<head><title>True</title></head>
</doc>""", tmpl.generate().render(encoding=None))
def test_match_with_xpath_variable(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<span py:match="*[name()=$tagname]">
Hello ${select('@name')}
</span>
<greeting name="Dude"/>
</div>""")
self.assertEqual("""<div>
<span>
Hello Dude
</span>
</div>""", tmpl.generate(tagname='greeting').render(encoding=None))
self.assertEqual("""<div>
<greeting name="Dude"/>
</div>""", tmpl.generate(tagname='sayhello').render(encoding=None))
def test_content_directive_in_match(self):
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<div py:match="foo">I said <q py:content="select('text()')">something</q>.</div>
<foo>bar</foo>
</html>""")
self.assertEqual("""<html>
<div>I said <q>bar</q>.</div>
</html>""", tmpl.generate().render(encoding=None))
def test_cascaded_matches(self):
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<body py:match="body">${select('*')}</body>
<head py:match="head">${select('title')}</head>
<body py:match="body">${select('*')}<hr /></body>
<head><title>Welcome to Markup</title></head>
<body><h2>Are you ready to mark up?</h2></body>
</html>""")
self.assertEqual("""<html>
<head><title>Welcome to Markup</title></head>
<body><h2>Are you ready to mark up?</h2><hr/></body>
</html>""", tmpl.generate().render(encoding=None))
def test_multiple_matches(self):
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<input py:match="form//input" py:attrs="select('@*')"
value="${values[str(select('@name'))]}" />
<form><p py:for="field in fields">
<label>${field.capitalize()}</label>
<input type="text" name="${field}" />
</p></form>
</html>""")
fields = ['hello_%s' % i for i in range(5)]
values = dict([('hello_%s' % i, i) for i in range(5)])
self.assertEqual("""<html>
<form><p>
<label>Hello_0</label>
<input value="0" type="text" name="hello_0"/>
</p><p>
<label>Hello_1</label>
<input value="1" type="text" name="hello_1"/>
</p><p>
<label>Hello_2</label>
<input value="2" type="text" name="hello_2"/>
</p><p>
<label>Hello_3</label>
<input value="3" type="text" name="hello_3"/>
</p><p>
<label>Hello_4</label>
<input value="4" type="text" name="hello_4"/>
</p></form>
</html>""", tmpl.generate(fields=fields, values=values)
.render(encoding=None))
def test_namespace_context(self):
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
xmlns:x="http://www.example.org/">
<div py:match="x:foo">Foo</div>
<foo xmlns="http://www.example.org/"/>
</html>""")
# FIXME: there should be a way to strip out unwanted/unused namespaces,
# such as the "x" in this example
self.assertEqual("""<html xmlns:x="http://www.example.org/">
<div>Foo</div>
</html>""", tmpl.generate().render(encoding=None))
def test_match_with_position_predicate(self):
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<p py:match="body/p[1]" class="first">${select('*|text()')}</p>
<body>
<p>Foo</p>
<p>Bar</p>
</body>
</html>""")
self.assertEqual("""<html>
<body>
<p class="first">Foo</p>
<p>Bar</p>
</body>
</html>""", tmpl.generate().render(encoding=None))
def test_match_with_closure(self):
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<p py:match="body//p" class="para">${select('*|text()')}</p>
<body>
<p>Foo</p>
<div><p>Bar</p></div>
</body>
</html>""")
self.assertEqual("""<html>
<body>
<p class="para">Foo</p>
<div><p class="para">Bar</p></div>
</body>
</html>""", tmpl.generate().render(encoding=None))
def test_match_without_closure(self):
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<p py:match="body/p" class="para">${select('*|text()')}</p>
<body>
<p>Foo</p>
<div><p>Bar</p></div>
</body>
</html>""")
self.assertEqual("""<html>
<body>
<p class="para">Foo</p>
<div><p>Bar</p></div>
</body>
</html>""", tmpl.generate().render(encoding=None))
def test_match_with_once_attribute(self):
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<py:match path="body" once="true"><body>
<div id="wrap">
${select("*")}
</div>
</body></py:match>
<body>
<p>Foo</p>
</body>
<body>
<p>Bar</p>
</body>
</html>""")
self.assertEqual("""<html>
<body>
<div id="wrap">
<p>Foo</p>
</div>
</body>
<body>
<p>Bar</p>
</body>
</html>""", tmpl.generate().render(encoding=None))
def test_match_with_recursive_attribute(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:match path="elem" recursive="false"><elem>
<div class="elem">
${select('*')}
</div>
</elem></py:match>
<elem>
<subelem>
<elem/>
</subelem>
</elem>
</doc>""")
self.assertEqual("""<doc>
<elem>
<div class="elem">
<subelem>
<elem/>
</subelem>
</div>
</elem>
</doc>""", tmpl.generate().render(encoding=None))
# See http://genshi.edgewall.org/ticket/254/
def test_triple_match_produces_no_duplicate_items(self):
tmpl = MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<div py:match="div[@id='content']" py:attrs="select('@*')" once="true">
<ul id="tabbed_pane" />
${select('*')}
</div>
<body py:match="body" once="true" buffer="false">
${select('*|text()')}
</body>
<body py:match="body" once="true" buffer="false">
${select('*|text()')}
</body>
<body>
<div id="content">
<h1>Ticket X</h1>
</div>
</body>
</doc>""")
output = tmpl.generate().render('xhtml', doctype='xhtml')
matches = re.findall("tabbed_pane", output)
self.assertNotEqual(None, matches)
self.assertEqual(1, len(matches))
def test_match_multiple_times1(self):
# See http://genshi.edgewall.org/ticket/370
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<py:match path="body[@id='content']/h2" />
<head py:match="head" />
<head py:match="head" />
<head />
<body />
</html>""")
self.assertEqual("""<html>
<head/>
<body/>
</html>""", tmpl.generate().render())
def test_match_multiple_times2(self):
# See http://genshi.edgewall.org/ticket/370
tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
<py:match path="body/div[@id='properties']" />
<head py:match="head" />
<head py:match="head" />
<head/>
<body>
<div id="properties">Foo</div>
</body>
</html>""")
self.assertEqual("""<html>
<head/>
<body>
</body>
</html>""", tmpl.generate().render())
def test_match_multiple_times3(self):
# See http://genshi.edgewall.org/ticket/370#comment:12
tmpl = MarkupTemplate("""<?xml version="1.0"?>
<root xmlns:py="http://genshi.edgewall.org/">
<py:match path="foo/bar">
<zzzzz/>
</py:match>
<foo>
<bar/>
<bar/>
</foo>
<bar/>
</root>""")
self.assertEqual("""<?xml version="1.0"?>\n<root>
<foo>
<zzzzz/>
<zzzzz/>
</foo>
<bar/>
</root>""", tmpl.generate().render())
# FIXME
#def test_match_after_step(self):
# tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
# <span py:match="div/greeting">
# Hello ${select('@name')}
# </span>
# <greeting name="Dude" />
# </div>""")
# self.assertEqual("""<div>
# <span>
# Hello Dude
# </span>
# </div>""", tmpl.generate().render(encoding=None))
class ContentDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:content` template directive."""
def test_as_element(self):
try:
MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<py:content foo="">Foo</py:content>
</doc>""", filename='test.html').generate()
self.fail('Expected TemplateSyntaxError')
except TemplateSyntaxError as e:
self.assertEqual('test.html', e.filename)
self.assertEqual(2, e.lineno)
class ReplaceDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:replace` template directive."""
def test_replace_with_empty_value(self):
"""
Verify that the directive raises an apprioriate exception when an empty
expression is supplied.
"""
try:
MarkupTemplate("""<doc xmlns:py="http://genshi.edgewall.org/">
<elem py:replace="">Foo</elem>
</doc>""", filename='test.html').generate()
self.fail('Expected TemplateSyntaxError')
except TemplateSyntaxError as e:
self.assertEqual('test.html', e.filename)
self.assertEqual(2, e.lineno)
def test_as_element(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<py:replace value="title" />
</div>""", filename='test.html')
self.assertEqual("""<div>
Test
</div>""", tmpl.generate(title='Test').render(encoding=None))
class StripDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:strip` template directive."""
def test_strip_false(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<div py:strip="False"><b>foo</b></div>
</div>""")
self.assertEqual("""<div>
<div><b>foo</b></div>
</div>""", tmpl.generate().render(encoding=None))
def test_strip_empty(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<div py:strip=""><b>foo</b></div>
</div>""")
self.assertEqual("""<div>
<b>foo</b>
</div>""", tmpl.generate().render(encoding=None))
class WithDirectiveTestCase(unittest.TestCase):
"""Tests for the `py:with` template directive."""
def test_shadowing(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
${x}
<span py:with="x = x * 2" py:replace="x"/>
${x}
</div>""")
self.assertEqual("""<div>
42
84
42
</div>""", tmpl.generate(x=42).render(encoding=None))
def test_as_element(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<py:with vars="x = x * 2">${x}</py:with>
</div>""")
self.assertEqual("""<div>
84
</div>""", tmpl.generate(x=42).render(encoding=None))
def test_multiple_vars_same_name(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<py:with vars="
foo = 'bar';
foo = foo.replace('r', 'z')
">
$foo
</py:with>
</div>""")
self.assertEqual("""<div>
baz
</div>""", tmpl.generate(x=42).render(encoding=None))
def test_multiple_vars_single_assignment(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<py:with vars="x = y = z = 1">${x} ${y} ${z}</py:with>
</div>""")
self.assertEqual("""<div>
1 1 1
</div>""", tmpl.generate(x=42).render(encoding=None))
def test_nested_vars_single_assignment(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<py:with vars="x, (y, z) = (1, (2, 3))">${x} ${y} ${z}</py:with>
</div>""")
self.assertEqual("""<div>
1 2 3
</div>""", tmpl.generate(x=42).render(encoding=None))
def test_multiple_vars_trailing_semicolon(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<py:with vars="x = x * 2; y = x / 2;">${x} ${y}</py:with>
</div>""")
self.assertEqual("""<div>
84 %s
</div>""" % (84 / 2), tmpl.generate(x=42).render(encoding=None))
def test_semicolon_escape(self):
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<py:with vars="x = 'here is a semicolon: ;'; y = 'here are two semicolons: ;;' ;">
${x}
${y}
</py:with>
</div>""")
self.assertEqual("""<div>
here is a semicolon: ;
here are two semicolons: ;;
</div>""", tmpl.generate().render(encoding=None))
def test_ast_transformation(self):
"""
Verify that the usual template expression AST transformations are
applied despite the code being compiled to a `Suite` object.
"""
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<span py:with="bar=foo.bar">
$bar
</span>
</div>""")
self.assertEqual("""<div>
<span>
42
</span>
</div>""", tmpl.generate(foo={'bar': 42}).render(encoding=None))
def test_unicode_expr(self):
tmpl = MarkupTemplate(u"""<div xmlns:py="http://genshi.edgewall.org/">
<span py:with="weeks=(u'一', u'二', u'三', u'四', u'五', u'六', u'日')">
$weeks
</span>
</div>""")
self.assertEqual(u"""<div>
<span>
一二三四五六日
</span>
</div>""", tmpl.generate().render(encoding=None))
def test_with_empty_value(self):
"""
Verify that an empty py:with works (useless, but legal)
"""
tmpl = MarkupTemplate("""<div xmlns:py="http://genshi.edgewall.org/">
<span py:with="">Text</span></div>""")
self.assertEqual("""<div>
<span>Text</span></div>""", tmpl.generate().render(encoding=None))
def suite():
suite = unittest.TestSuite()
suite.addTest(doctest.DocTestSuite(directives))
suite.addTest(unittest.makeSuite(AttrsDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(ChooseDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(DefDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(ForDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(IfDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(MatchDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(ContentDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(ReplaceDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(StripDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(WithDirectiveTestCase, 'test'))
return suite
if __name__ == '__main__':
unittest.main(defaultTest='suite')