def __init__( self, path, reload=True, force_mode=None, autoescape_text=False, xml_autoblocks=None, **template_options ): super().__init__() from kajiki import TextTemplate, XMLTemplate if isinstance(path, str): self.path = path.split(";") else: self.path = path self._timestamps = {} self._reload = reload self._force_mode = force_mode self._autoescape_text = autoescape_text self._xml_autoblocks = xml_autoblocks self._template_options = template_options self.extension_map = dict( txt=lambda *a, **kw: TextTemplate( autoescape=self._autoescape_text, *a, **kw ), xml=XMLTemplate, html=lambda *a, **kw: XMLTemplate(mode="html", *a, **kw), html5=lambda *a, **kw: XMLTemplate(mode="html5", *a, **kw), )
def test_substituting_gettext_with_lambda_extending(self): loader = MockLoader({ "parent.html": XMLTemplate("""<div>parent</div>"""), "child.html": XMLTemplate( """<py:extends href="parent.html"><div>child</div></py:extends>""" ), }) tpl = loader.import_("child.html") rsp = tpl(dict(gettext=lambda _: "egg")).render() assert rsp == """<div>egg</div><div>egg</div>""", rsp
def test_substituting_gettext_with_lambda_extending(self): gettext = lambda x: 'egg' loader = MockLoader({ 'parent.html': XMLTemplate('''<div>parent</div>'''), 'child.html': XMLTemplate( '''<py:extends href="parent.html"><div>child</div></py:extends>''' ) }) tpl = loader.import_('child.html') rsp = tpl(dict(gettext=gettext)).render() assert rsp == '''<div>egg</div><div>egg</div>''', rsp
def _load(self, name, encoding='utf-8', *args, **kwargs): '''Text templates are read in text mode and XML templates are read in binary mode. Thus, the ``encoding`` argument is only used for reading text template files. ''' from kajiki import XMLTemplate, TextTemplate filename = self._filename(name) self._timestamps[name] = os.stat(filename).st_mtime if self._force_mode == 'text': return TextTemplate(filename=filename, autoescape=self._autoescape_text, *args, **kwargs) elif self._force_mode: return XMLTemplate(filename=filename, mode=self._force_mode, autoblocks=self._xml_autoblocks, *args, **kwargs) else: ext = os.path.splitext(filename)[1][1:] return self.extension_map[ext](source=None, filename=filename, *args, **kwargs)
def _load(self, name, encoding="utf-8", *args, **kwargs): """Text templates are read in text mode and XML templates are read in binary mode. Thus, the ``encoding`` argument is only used for reading text template files. """ from kajiki import TextTemplate, XMLTemplate options = self._template_options.copy() options.update(kwargs) filename = self._filename(name) if filename is None: raise IOError("Unknown template %r" % name) self._timestamps[name] = os.stat(filename).st_mtime if self._force_mode == "text": return TextTemplate( filename=filename, autoescape=self._autoescape_text, *args, **options ) elif self._force_mode: return XMLTemplate( filename=filename, mode=self._force_mode, autoblocks=self._xml_autoblocks, *args, **options ) else: ext = os.path.splitext(filename)[1][1:] return self.extension_map[ext]( source=None, filename=filename, *args, **options )
def test_include(self): """Must NOT result in: NameError: global name 'name' is not defined""" loader = MockLoader({ "included.html": XMLTemplate("<p>The included template must also " "access Kajiki globals and the template context: " '${value_of("name")}</p>\n'), "tpl.html": XMLTemplate("<html><body><p>This is the body</p>\n" '<py:include href="included.html"/></body></html>'), }) tpl = loader.import_("tpl.html") rsp = tpl(dict(name="Rick")).render() assert ("<html><body><p>This is the body</p>\n" "<p>The included template must also access Kajiki globals and " "the template context: Rick</p></body></html>" == rsp)
def test_only_comment(self): try: XMLTemplate("<!-- a -->") except XMLTemplateParseError as e: assert "no element found" in str(e), e else: assert False, "should have raised"
def test_substituting_gettext_with_lambda_extending_twice(self): loader = MockLoader({ "parent.html": XMLTemplate("<div>parent</div>"), "mid.html": XMLTemplate( '<py:extends href="parent.html"><div>${variable}</div></py:extends>' ), "child.html": XMLTemplate( '<py:extends href="mid.html"><div>child</div></py:extends>'), }) tpl = loader.import_("child.html") rsp = tpl(dict(variable="spam", gettext=lambda _: "egg")).render() # variables must not be translated assert rsp == """<div>egg</div><div>spam</div><div>egg</div>""", rsp
def test_include(self): '''Must NOT result in: NameError: global name 'name' is not defined''' loader = MockLoader({ 'included.html': XMLTemplate('<p>The included template must also ' 'access Kajiki globals and the template context: ' '${value_of("name")}</p>\n'), 'tpl.html': XMLTemplate('<html><body><p>This is the body</p>\n' '<py:include href="included.html"/></body></html>') }) tpl = loader.import_('tpl.html') rsp = tpl(dict(name='Rick')).render() assert ('<html><body><p>This is the body</p>\n' '<p>The included template must also access Kajiki globals and ' 'the template context: Rick</p></body></html>' == rsp)
def test_multiple_nodes(self): try: XMLTemplate("<!-- a --><x>${1+1}</x><y>${1+1}</y>") except XMLTemplateParseError as e: assert "junk after document element" in str(e), e else: assert False, "should have raised"
def test_raise_plus_with_an_operand(self): try: XMLTemplate('<x>${"ciao" + }</x>') assert False, "must raise" except XMLTemplateCompileError as e: assert "detected an invalid python expression" in str(e), e assert '"ciao" +' in str(e), e
def test_raise_unclosed_string(self): try: XMLTemplate('<x>${"ciao}</x>') assert False, "must raise" except XMLTemplateCompileError as e: # assert "can't compile" in str(e), e # different between pypy and cpython assert '"ciao' in str(e), e
def test_only_comment(self): try: XMLTemplate('<!-- a -->') except XMLTemplateParseError as e: assert 'no element found' in str(e), e else: assert False, 'should have raised'
def test_expr_multiline_and_IndentationError(self): try: XMLTemplate("""<div>Hello, ${ 'pippo' + 'baudo'}</div>""")().render() except XMLTemplateCompileError as e: assert "`'pippo' +\n 'baudo'`" in str(e), str(e) assert "Hello" in str(e) assert "baudo" in str(e)
def test_raise(self): try: XMLTemplate(u'''<div py:strip="True" ><py:def function="echo(x)">$x</py:def >${echo('hello'))}</div>''') assert False, 'should raise' except XMLTemplateCompileError as e: pass
def test_raise(self): try: XMLTemplate("""<div py:strip="True" ><py:def function="echo(x)">$x</py:def >${echo('hello'))}</div>""") assert False, "should raise" except XMLTemplateCompileError: pass
def test_autoblocks_disabling(self): loader = MockLoader({ "parent.html": XMLTemplate( """ <html py:strip=""> <head></head> <body py:autoblock="False"> <p py:block="body">It was good seeing you last Friday. Thanks for the gift!</p> </body> </html>""", autoblocks=["body"], ), "child.html": XMLTemplate( """ <html> <py:extends href="parent.html"/> <body><em>Great conference this weekend!</em></body> </html>""", autoblocks=["body"], ), }) parent = loader.import_("parent.html") rsp = parent().render() assert (rsp == """ <head/> <body> <p>It was good seeing you last Friday. Thanks for the gift!</p> </body> """), rsp child = loader.import_("child.html") rsp = child().render() assert (rsp == """<html> <head/> <body> <em>Great conference this weekend!</em> </body> </html>"""), rsp
def test_block(self): loader = MockLoader({ 'parent.html': XMLTemplate('''<div ><py:def function="greet(name)" >Hello, $name!</py:def ><py:def function="sign(name)" >Sincerely,<br/><em>$name</em></py:def >${greet(to)} <p py:block="body">It was good seeing you last Friday. Thanks for the gift!</p> ${sign(from_)} </div>'''), 'child.html': XMLTemplate('''<py:extends href="parent.html" ><py:def function="greet(name)" >Dear $name:</py:def ><py:block name="body">${parent_block()} <p>And don't forget you owe me money!</p> </py:block ></py:extends> ''') }) parent = loader.import_('parent.html') rsp = parent({'to': 'Mark', 'from_': 'Rick'}).render() assert rsp == '''<div>Hello, Mark! <p>It was good seeing you last Friday. Thanks for the gift!</p> Sincerely,<br/><em>Rick</em> </div>''', rsp child = loader.import_('child.html') rsp = child({'to': 'Mark', 'from_': 'Rick'}).render() assert rsp == '''<div>Dear Mark: <p>It was good seeing you last Friday. Thanks for the gift!</p> <p>And don't forget you owe me money!</p> Sincerely,<br/><em>Rick</em> </div>''', rsp
def test_block(self): loader = MockLoader({ "parent.html": XMLTemplate("""<div ><py:def function="greet(name)" >Hello, $name!</py:def ><py:def function="sign(name)" >Sincerely,<br/><em>$name</em></py:def >${greet(to)} <p py:block="body">It was good seeing you last Friday. Thanks for the gift!</p> ${sign(from_)} </div>"""), "child.html": XMLTemplate("""<py:extends href="parent.html" ><py:def function="greet(name)" >Dear $name:</py:def ><py:block name="body">${parent_block()} <p>And don't forget you owe me money!</p> </py:block ></py:extends> """), }) parent = loader.import_("parent.html") rsp = parent({"to": "Mark", "from_": "Rick"}).render() assert (rsp == """<div>Hello, Mark! <p>It was good seeing you last Friday. Thanks for the gift!</p> Sincerely,<br/><em>Rick</em> </div>"""), rsp child = loader.import_("child.html") rsp = child({"to": "Mark", "from_": "Rick"}).render() assert (rsp == """<div>Dear Mark: <p>It was good seeing you last Friday. Thanks for the gift!</p> <p>And don't forget you owe me money!</p> Sincerely,<br/><em>Rick</em> </div>"""), rsp
def test_substituting_gettext_with_lambda_extending_twice(self): gettext = lambda x: 'egg' loader = MockLoader({ 'parent.html': XMLTemplate('''<div>parent</div>'''), 'mid.html': XMLTemplate( '''<py:extends href="parent.html"><div>${variable}</div></py:extends>''' ), 'child.html': XMLTemplate( '''<py:extends href="mid.html"><div>child</div></py:extends>''' ) }) tpl = loader.import_('child.html') rsp = tpl(dict(variable='spam', gettext=gettext)).render() # variables must not be translated assert rsp == '''<div>egg</div><div>spam</div><div>egg</div>''', rsp
def test_dynamic(self): loader = MockLoader({ 'parent0.html': XMLTemplate('<span>Parent 0</span>'), 'parent1.html': XMLTemplate('<span>Parent 1</span>'), 'child.html': XMLTemplate('''<div ><py:if test="p == 0"><py:extends href="parent0.html"/></py:if ><py:else><py:extends href="parent1.html"/></py:else ></div> ''') }) tpl = loader.import_('child.html') rsp = tpl(dict(p=0)).render() assert rsp == '<div><span>Parent 0</span></div>', rsp rsp = tpl(dict(p=1)).render() assert rsp == '<div><span>Parent 1</span></div>', rsp
def test_dynamic(self): loader = MockLoader({ "parent0.html": XMLTemplate("<span>Parent 0</span>"), "parent1.html": XMLTemplate("<span>Parent 1</span>"), "child.html": XMLTemplate("""<div ><py:if test="p == 0"><py:extends href="parent0.html"/></py:if ><py:else><py:extends href="parent1.html"/></py:else ></div> """), }) tpl = loader.import_("child.html") rsp = tpl(dict(p=0)).render() assert rsp == "<div><span>Parent 0</span></div>", rsp rsp = tpl(dict(p=1)).render() assert rsp == "<div><span>Parent 1</span></div>", rsp
def test_basic(self): loader = MockLoader({ "parent.html": XMLTemplate("""<div ><h1 py:def="header()">Header name=$name</h1 ><h6 py:def="footer()">Footer</h6 ><div py:def="body()"> id() = ${id()} local.id() = ${local.id()} self.id() = ${self.id()} child.id() = ${child.id()} </div><span py:def="id()">parent</span> ${header()} ${body()} ${footer()} </div>"""), "mid.html": XMLTemplate("""<py:extends href="parent.html" ><span py:def="id()">mid</span ></py:extends>"""), "child.html": XMLTemplate("""<py:extends href="mid.html" ><span py:def="id()">child</span ><div py:def="body()"> <h2>Child Body</h2> ${parent.body()} </div></py:extends>"""), }) tpl = loader.import_("child.html") rsp = tpl(dict(name="Rick")).render() assert (rsp == """<div> <h1>Header name=Rick</h1> <div> <h2>Child Body</h2> <div> id() = <span>child</span> local.id() = <span>parent</span> self.id() = <span>child</span> child.id() = <span>mid</span> </div> </div> <h6>Footer</h6> </div>"""), rsp
def test_basic(self): loader = MockLoader({ 'parent.html': XMLTemplate('''<div ><h1 py:def="header()">Header name=$name</h1 ><h6 py:def="footer()">Footer</h6 ><div py:def="body()"> id() = ${id()} local.id() = ${local.id()} self.id() = ${self.id()} child.id() = ${child.id()} </div><span py:def="id()">parent</span> ${header()} ${body()} ${footer()} </div>'''), 'mid.html': XMLTemplate('''<py:extends href="parent.html" ><span py:def="id()">mid</span ></py:extends>'''), 'child.html': XMLTemplate('''<py:extends href="mid.html" ><span py:def="id()">child</span ><div py:def="body()"> <h2>Child Body</h2> ${parent.body()} </div></py:extends>''') }) tpl = loader.import_('child.html') rsp = tpl(dict(name='Rick')).render() assert rsp == '''<div> <h1>Header name=Rick</h1> <div> <h2>Child Body</h2> <div> id() = <span>child</span> local.id() = <span>parent</span> self.id() = <span>child</span> child.id() = <span>mid</span> </div> </div> <h6>Footer</h6> </div>''', rsp
def test_leading_opening_brace(self): if sys.version_info[:2] == (2, 6): raise SkipTest( 'Python 2.6 compiler raises a different kind of error') try: XMLTemplate('<x>${{"a", "b"}</x>') assert False, 'must raise' except XMLTemplateCompileError as e: assert 'Braced expression not terminated' in str(e), e
def test_autoblocks_disabling(self): loader = MockLoader({ 'parent.html': XMLTemplate(''' <html py:strip=""> <head></head> <body py:autoblock="False"> <p py:block="body">It was good seeing you last Friday. Thanks for the gift!</p> </body> </html>''', autoblocks=['body']), 'child.html': XMLTemplate(''' <html> <py:extends href="parent.html"/> <body><em>Great conference this weekend!</em></body> </html>''', autoblocks=['body']) }) parent = loader.import_('parent.html') rsp = parent().render() assert rsp == ''' <head/> <body> <p>It was good seeing you last Friday. Thanks for the gift!</p> </body> ''', rsp child = loader.import_('child.html') rsp = child().render() assert rsp == '''<html> <head/> <body> <em>Great conference this weekend!</em> </body> </html>''', rsp
def perform(source, expected_output, context=dict(name="Rick"), **options): tpl = XMLTemplate(source, **options) try: rsp = tpl(context).render() assert isinstance(rsp, str), "render() must return a unicode string." assert rsp == expected_output, (rsp, expected_output) except Exception as e: print("\n" + tpl.py_text) raise e else: return tpl
def test_import(self): loader = MockLoader({ "lib.html": XMLTemplate(source="""<div> <span py:def="evenness(n)" ><py:if test="n % 2 == 0" >even</py:if ><py:else >odd</py:else ></span> <py:def function="half_evenness(n)" >half of $n is ${evenness(n/2)}</py:def> </div>"""), "tpl.html": XMLTemplate(source="""<div> <py:import href="lib.html" alias="simple_function" /><ul> <li py:for="i in range(4)"> $i is ${simple_function.evenness(i)} ${simple_function.half_evenness(i)} </li> </ul> </div>"""), }) tpl = loader.import_("tpl.html") rsp = tpl(dict(name="Rick")).render() assert (rsp == """<div> <ul> <li> 0 is <span>even</span> half of 0 is <span>even</span> </li><li> 1 is <span>odd</span> half of 1 is <span>odd</span> </li><li> 2 is <span>even</span> half of 2 is <span>odd</span> </li><li> 3 is <span>odd</span> half of 3 is <span>odd</span> </li> </ul> </div>"""), rsp
def test_import_auto(self): loader = MockLoader({ 'lib.html': XMLTemplate(source='''<div> <span py:def="evenness(n)" ><py:if test="n % 2 == 0" >even</py:if ><py:else >odd</py:else ></span> <py:def function="half_evenness(n)" >half of $n is ${evenness(n/2)}</py:def> </div>'''), 'tpl.html': XMLTemplate(source='''<div> <py:import href="lib.html" /><ul> <li py:for="i in range(4)"> $i is ${lib.evenness(i)} ${lib.half_evenness(i)} </li> </ul> </div>''') }) tpl = loader.import_('tpl.html') rsp = tpl(dict(name='Rick')).render() assert rsp == '''<div> <ul> <li> 0 is <span>even</span> half of 0 is <span>even</span> </li><li> 1 is <span>odd</span> half of 1 is <span>odd</span> </li><li> 2 is <span>even</span> half of 2 is <span>odd</span> </li><li> 3 is <span>odd</span> half of 3 is <span>odd</span> </li> </ul> </div>''', rsp
def __init__(self, path, reload=True, force_mode=None, autoescape_text=False, xml_autoblocks=None): super(FileLoader, self).__init__() from kajiki import XMLTemplate, TextTemplate if isinstance(path, basestring): self.path = path.split(';') else: self.path = path self._timestamps = {} self._reload = reload self._force_mode = force_mode self._autoescape_text = autoescape_text self._xml_autoblocks = xml_autoblocks self.extension_map = dict( txt=lambda *a, **kw: TextTemplate( autoescape=self._autoescape_text, *a, **kw), xml=XMLTemplate, html=lambda *a, **kw: XMLTemplate(mode='html', *a, **kw), html5=lambda *a, **kw: XMLTemplate(mode='html5', *a, **kw))