PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

28
KAJIKI THE FAST AND VALIDATED TEMPLATE ENGINE YOU WERE LOOKING FOR Alessandro Molina @__amol__ [email protected]

Transcript of PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Page 1: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

KAJIKITHE FAST AND VALIDATED TEMPLATE

ENGINE YOU WERE LOOKING FOR

Alessandro Molina@__amol__

[email protected]

Page 2: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Who am I

● Passionate Python Developer

● TurboGears2 core team member

● Beaker caching/session framework current maintainer

● Author of DukPy js env for Python and DEPOT file storage framework

● Contributor to Ming, ToscaWidgets2, Formencode, WebOb, Kajiki, ...

Page 3: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Why?

● There are tens of template engines out there, but people often only know the default one of their web framework.

● Different template engines can differ in important features, not just syntax.

● Working on one has been fun and interesting.

Page 4: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Template Engines

TYPE NAME URL

Markup + Streamed Genshi http://genshi.edgewall.org/

Text + Compiled Mako http://www.makotemplates.org/

Text + Compiled Jinja http://jinja.pocoo.org/

Markup + Compiled Kajiki http://kajiki.readthedocs.io/

Page 5: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

One more Template Engine?

● We loved the fact that Genshi templates could by opened with any HTML editor

● We loved Genshi syntax, concise and reflecting the output itself.

● We loved Genshi so much TG2.2 included it in all projects, to make it available for pluggable apps and extensions.

Page 6: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Right Timing...

Page 7: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

How I felt...

Page 8: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Well...

● Genshi was pretty complex. We didn’t want to maintain such complexity.

● Streaming was powerful but hard to use, very few people understood genshi inheritance. And it was really slow.

● A TG team member was experimenting with the idea of a similar engine.

Page 9: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Kajiki<html>

<head>

<title py:content="title">This is replaced.</title>

</head>

<body>

<p>These are some fruits:</p>

<ul>

<li py:for="fruit in fruits">

I like ${fruit}s

</li>

</ul>

</body>

</html>

Page 10: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Directives● py:if & py:else● py:switch & py:case & py:else● py:for● py:def● py:strip● py:with● py:attrs● py:block & py:extends● ...

Page 11: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

How It Works

● Your template is parsed and converted to Python code.

● Whenever the template is rendered the generated python code is executed.

● The python code is yielded by a generator that resembles the DOM of the document.

Page 12: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Architecture

PARSER

COMPILER

INTERMEDIATE REPRESENTATION

PYTHON

READ XML AND GENERATE DOM OUT OF IT WITH SAX

NAVIGATE DOM AND CREATE IR FOR ITS NODES

ITERATE THE IR NODES TO GENERATE PYTHON CODE

RUN PYTHON CODE TO RENDER TEMPLATE

Page 13: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Compiled Kajikiclass template:

@kajiki.expose

def __main__():

yield u'<html>\n <head>\n <title>'

yield self.__kj__.escape(title)

yield u'</title>\n </head>\n <body>\n <p>'

yield local.__kj__.gettext(u'These are some fruits:')

yield u'</p>\n <ul>\n '

for fruit in fruits:

yield u'<li>'

yield local.__kj__.gettext(u'\n I like ')

yield self.__kj__.escape(fruit)

yield local.__kj__.gettext(u's\n ')

yield u'</li>'

yield u'\n </ul>\n </body>\n</html>'

Page 14: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Rendered Kajiki<html>

<head>

<title>A Kajiki Template</title>

</head>

<body>

<p>These are some fruits:</p>

<ul>

<li>

I like oranges

</li><li>

I like apples

</li>

</ul>

</body>

</html>

Page 15: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

That makes it pretty Fast

● Mako

○ Rendered 1M mako templates in 22.217651844

● Kajiki

○ Rendered 1M Kajiki templates in 11.8710489273

%for user in users:

<span>Hello {{ user }}!</span>

%endfor

<span py:for="user in users">

Hello ${user}!

</span>

Page 16: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

It’s really just python! Mad science included!import kajiki

loader = kajiki.FileLoader('.', force_mode='xml')

tmpl = loader.load('mypage.kajiki')

with open('cython_test.pyx', 'wb') as pyx:

py_text = tmpl.py_text.replace('@kajiki.expose', '@staticmethod')

py_text = py_text.replace('__main__():', '__main__(self, local, users):')

py_text = py_text.replace('template = kajiki.Template(template)', '')

pyx.write(py_text)

import pyximport; pyximport.install()

import cython_test

class template:

@kajiki.expose

def __main__():

return cytmpl.__main__(self, local, users)

template = kajiki.Template(template)

print template(dict(cytmpl=cython_test.template, users=range(100000))).render()

Page 17: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Don’t try this at home

● Huge hack, but theoretically it can work. With minor tweaks Kajiki itself could generate cython compatible code.

● Rendering python 11.86215686798

● Rederning cython 9.07893800735

Page 18: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

But being Python is easy to debug

Page 19: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Integrates with Python debuggers

Page 20: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Python Syntax Checking

kajiki.template.KajikiSyntaxError: [<string>:9]

invalid syntax

yield local.__kj__.gettext(u'These are some of

my favorite fruits:')

yield u'</p>\n <ul>\n '

--> for fruit on fuits:

yield u'<li>'

yield local.__kj__.gettext(u'\n I like ')

Page 21: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Validated Templates

● As Kajiki understands the document you are writing (it’s not just text) it can take steps specific to HTML generation:○ Error Reporting○ Escaping○ Automatic i18n○ Minification

Page 22: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Malformed HTML Detection

kajiki.xml_template.XMLTemplateParseError:

[./plain.kajiki:10] mismatched tag

<li py:for="fruit in fruits">

I like ${fruit}s

--> </span>

</ul>

</body>

Page 23: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Escaping handled for us<li py:for="fruit in fruits">

I like ${fruit}s

</li>

template(dict(

fruits=['<apple>'],

title='A Kajiki Template'

)).render()

<li>

I like &lt;apple&gt;s

</li>

Page 24: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Easy Translations<li py:for="fruit in fruits">

I like ${fruit}s

</li>

for fruit on fuits:

yield u'<li>'

yield local.__kj__.gettext(u'\n I like ')

Page 25: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Minificationtmpl = loader.load('plain.kajiki', strip_text=False)

<ul>

<li>

I like oranges

</li><li>

I like apple

</li><li>

I like kiwis

</li>

</ul>

tmpl = loader.load('plain.kajiki', strip_text=True)

<ul><li>I like oranges</li><li>I like apple</li><li>I like

kiwis</li></ul>

Page 26: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Text engine available too>>> Template = kajiki.TextTemplate('''

... {%if foo %}

... bar

... {%else%}

... baz

... {%end%}

... ''')

>>> print(Template(dict(foo=True)).render())

bar

>>> print(Template(dict(foo=False)).render())

baz

Page 27: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Feel free to try it!

● Python 2.6, 2.7, 3.2, 3.3, 3.4 and 3.5

● pip install kajiki

● Come and try it!

https://github.com/nandoflorestan/kajiki

● Still young! Feel free to open issues, send

pull requests, suggest features!

Page 28: PyconIE 2016 - Kajiki, the fast and validated template engine your were looking for

Questions?