Package: mint
aboutusagesyntaxtagsattributesescapingpythonexpressionsloopsconditionscommentssimplificationinheritanceutilsCLIaboutmint- is small, fast and easy to use (x)html templates engine.
Implemented with python language.Why usemint?:single python moduleYou can copymint.pyto your project package and use it.minimalistic syntaxYour templates will become smaller and more readable due to
indent based syntax.works fastmintusesastpython module from standard library
(since python2.6, thank you Armin and co). So all templates compiles to
optimized python byte code (during first call) which works fast.smartmintknows about (x)html tags and attributes,
so you get smart escaping. (There is a plan to implement html
validation during rendering)not standing in your waymintdoes’t hide exceptions like some other template engines, and
shows line in your template file where exception was raisedTemplate engine was inspired by haml (a template engine written in ruby),
but some concepts were redisigned for simplification and adoptation to python world.Home page:https://github.com/riffm/mintIssue tracker:https://github.com/riffm/mint/issuesusageSimple API:>>> import mint
>>> loader = mint.Loader('./templates', cache=True)
>>> namespace = dict(a='a', b='b')
>>> result = loader.get_template('index.mint').render(**namespace)mint.Loaderaccepts names of directories and then search for template files
by name provided inget_template(name)call.syntaxmintsyntax is based on indention, so you see the document structure and
update document fast. You can move blocks of code and do not search for
begining of parent tag and where it ends.tagsJust use@character before tag name to render a tag:@tagnameWhymintdoes’t use%char, like haml do?
I think that@char is more readable and it is just third button on the keyboard,
so you type it by one hand (without finger gymnastics).
Next example shows tags structure:@html
    @head
    @bodyIndented tags@headand@bodyare children for tag@html(parent tag).Text is interpreted as text:@div
    @p
        Text of paragraphSo last example will be rendered as:<div>
    <p>
        Text of paragraph
    </p>
</div>By the way you can use short variant:@div
    @p Text of paragraphattributesTo define attributemintuses concept similar to method calls:@div.id(content)Previouse example will be rendered as:<div id="content"></div>To define multiple attributesmintuses (so called) chaining:@img.alt().src(/img/my_picture.png)Previouse example will be rendered as:<img alt="" src="/img/my_picture.png" />Note thatmintknows about selfclosed html tags.Why do not use python dictionary declaration syntax instead?
Something like{alt:"",src:"/img/my_picture.png"}Because it is overloaded for html templating. “Chained-methods-call” like
syntax uses less chars to type.mintalows to set/append value of tag attribute somewhere inside tag:@div.class(main)
    // set value of attribute
    @.class(header)

@div.class(main)
    // append value to attribute
    @+class( header)will be rendered as:<div class="header"></div>

<div class="main header"></div>This is very handy when you need to set content of tag and it’s attributes based
on some condition.escapingAs you know there are some chars we need to escape in xml.  Andmintdoes this
automatically for you. It escapes all text inside tags and attributes.
Autoescaping can’t be turned off:@a.href(/docs?type=1&published=true) docs
@p.class( ' " < > & )
    <div class="inside" />Will be rendered as:<a href="/docs?type=1&amp;published=true">docs</a>
<p class="&#39; &quot; &lt; &gt; &amp;">
    &lt;div class=&quot;inside&quot; /&gt;
</p>python expressionsOf course, template engine without possibility to insert python expressions is unusable.
So inmintyou can do this with syntax similar tojinja2ordjango:@html
    @head
        @title {{ doc.title }}
    @body
        @div.id(content)
            Here we have content {{ doc.content }}Under the hoodmintcallsunicodeon python expression
and escapes result.Note that you can provide any valid python expression between tokens{{}}.
Also note that you can use limited subset of python__builtins__.Inminttemplates expressions can be used inside text elements and inside attributes:@p.class(title {{ doc.main_doc_class }}).id({{ doc.id }}) {{ doc.body }}As you remember all content inserted in tags (as text) and in attributes is
escaped bymint.  And this is good, but sometimes you need to insert
unescaped html.  For this purpose mint uses special classmint.Markup, which
implements__html__method (this is something like convention). To insert
html inside templates you need to mark your python variables withmint.Markupinside your python code.In previous example ifdoc.bodyhas html we need attributebodyto returnmint.Markup(html_string). And thathtml_stringwill be inserted in template
without escaping. That is the preferred way to insert markup inside html template.Also note that there are two contexts to insert markup - tag and attribute.
In case of tagmint.Markupinstances will be inserted without modifications.
But if you attemted to insert markup in attribute it will be additionaly escaped.For example we have such python code:class Doc(object):
    def __init__(self, title, body):
        self.title = mint.Markup(title)
        self.body = mint.Markup(body)

doc = Doc('<b>title</b>', '<p>content of document</p>')And such template:@div.class(doc)
    @p.class(title).title({{ doc.title }}) {{ doc.title }}
    {{ doc.body }}The result will be:<div class="doc">
    <p class="title" title="&gt;b&lt;title&gt;/b&lt;">
        <b>title</b>
    </p>
    <p>content of document</p>
</div>This feature ofmintis very handy.loopsInmintyou can use python statementfor:@ul
    #for img in images:
        @li @img.src({{ img.file }})Note that:@li @img.src({{ img.file }})is similar to:@li
    @img.src({{ img.file }})This is inline tags notation.conditionsConditions are easy to write too:#for doc in docs:
    #if doc.id != current_id:
        @a.href({{ url_for('doc', id=doc.id) }}) {{ doc.title }}
    #elif doc.title == 'I need paragraph':
        @p {{ doc.title }}
    #else:
        {{ doc.title }}commentsTo comment a line use token//:// In this div we provide content, yours C.O.
@div.id(content)Xml comments are supported, use token--:-- In this div we provide content, yours C.O.
@div.id(content)to get:<!-- In this div we provide content, yours C.O. -->
<div id="content"></div>Sometimes you need to use special tokens in text, so if a line starts with
token\line is not interpreted bymint:@p.class(title) Here we have title
\@p.class(title) Here we have titleWill provide:<p class="title">Here we have title</p>
@p.class(title) Here we have titlesimplificationSimplification of syntax provides ambiguity. But it is very handy sometimes.
Inminttemplates you can write such things:@ul
    #for image in images:
        @li.class(image) @img.alt().src({{ image.path }})This simplification alows to write nested tags in one line, one by one. In
previous example allimgtags will be insideli.Remember rule #1: This records:@div.id(1) @div.id(2) @div.id(3)

@div.id(1)
    @div.id(2) @div.id(3)

@div.id(1)
    @div.id(2)
        @div.id(3)are the same.Rule #2: you can append text to and only to last tag when you use syntax
simplification:@ul
    #for doc in docs:
        @li @p.class(title) {{ doc.title }}
            @p.class(descr) {{ doc.description }}liwill be rendered as:<li>
    <p class="title">...</p>
    <p class="descr">...</p>
</li>Be careful when using syntax simplification.inheritancemintuses slots to implement template inheritance. Slot is nothing more but
python function that retuns markup. Slot can be defined and called anywhere in template:// layout.mint
@html
    @head
        @title {{ title }}
    @body
        @div.id(content)

            #def content():
                @p.class(title) {{ title }}
                {{ text }}

            #content()

        @div.id(footer)As you can see in previous example we define slotcontentand call it after that.
During call of slot it’s content will be inserted in template. And if we need to insert
different content in that place we should inheritlayout.mintand overridecontentslot implementation:// news.mint
#base: layout.mint

#def content():
    #for item in news:
        @a.href({{ url_for('news-item', id=item.id) }}) {{ news.title }}It is simple and powerful concept.Slots are python functions, so they see all global variables passed to template and have
own scope. This is very handy, because sometimes people have problems with such things
in other templates engines.For example we need a block insideforloop:// layout.mint
@div.id(content)
    #for item in items:
        #loop_slot()

// photos.mint
#base: layout.mint

#def loop_slot():
    @p.class(title) {{ item.title }}
    @img.alt().src({{ item.image.path }})Formintthis is natural behavior. Anditemis just global variable for
slotloop_slot. But in this case it’s better to provideitemto slot
explicitly:// layout.mint
@div.id(content)
    #for item in items:
        #loop_slot(item)

// photos.mint
#base: layout.mint

#def loop_slot(item):
    @p.class(title) {{ item.title }}
    @img.alt().src({{ item.image.path }})Also we can call base slot inside overrided slot. In our case base slot will
point to slot with same name in our base template.__base__variable points
inside current slot scope to implementation of current slot in parent template:// base.mint
-- somewhere in head tag
#def js():
    @script.type(text/javascript).src(/js/main.js)
#js()


// photos.mint
#base: base.mint
#def js():
    #__base__()
    @script.type(text/javascript).src(/js/photos.js)This example will results in:<!-- somewhere in head tag -->
<script type="text/javascript" scr="/js/main.js"></script>
<script type="text/javascript" scr="/js/photos.js"></script>Slots are plain python functions, slots returnsMarkupobjects so we can pass slots
or result of slot call to other slots.And more. We can use slots outside of templates. Lets take photos.mint from
example withforloop:>>> import mint
>>> t = mint.Loader('.').get_template('photos.mint')
>>> loop_slot = t.slot('loop_slot')
>>> # lets take image somewhere
>>> item = images.get(1)
>>> loop_slot(item)
Markup(u'<p class="title">...</p><img alt="" src="..." />')But sometimes slots needs global variables, you must provide such variables
with kwargs in methodslot(name, **globals)ofTemplateobject.utilsmintprovides global variableutilswhich contains useful constants and helper
functions.Doctype declarationsutils.doctype.html_strictutils.doctype.html_transitionalutils.doctype.xhtml_strictutils.doctype.xhtml_transitionalExample of usage:{{ utils.doctype.html_strict }}
@htmlClassmint.Markupisutils.markup(this is replacement for hack{{ var|safe }})utils.loopis helper function to use withforstatement. It takes iterable
object and returns tuple of item and special object that consist of useful info for each
iteration:#for item, l in utils.loop(items):
    @a.href({{ item.url }})
        {{ item.title }} {{ (l.first, l.last, l.odd) }} {{ l.cycle('one', 'two', 'three') }}In previous examplel.cycle('one','two', 'three')will return one of values provided
in sequence. It is handy to colorize tables.Html helpersutils.scriptutils.scriptsutils.linkCommand Line Interfaceminthas a CLI. To list available options use--helpflag:% python -m mint --help
Usage: mint.py [options] [template]

Options:
  -h, --help        show this help message and exit
  -c, --code        Show only python code of compiled template.
  -t, --tokenize    Show tokens stream of template.
  -r N, --repeat=N  Try to render template N times and display average time
                    result.
  -p, --pprint      Turn pretty print on.
  -m, --monitor     Monitor current directory and subdirectories for changes
                    in mint files. And render corresponding html files.CLI works in two modes:renderingmonitoringThat’s all folks!changelogv0.5Smart indent. Tokenizer setsindent levelfor whole template equal indent
level of first indented line (as in python)Mint nodes now based onast.ASTand to transformminttree topythontree we useast.NodeTransformersubclass. This feature allows us write
transformers for other languages (js =)Addedpretty printingof html result. Default indention is two spaces and
is unchangableUpdated vim highlight for mint filesAdded html helpersutils.script,utils.linkandutils.scriptsNewCLIinterface. Some featuresshows result python code listing for mint templateshows tokens stream for mint templaterenders templates and prints result to stdout (note: if no outer variables
used)measures average rendering time for template (note: if no outer variables
used)monitoringfeatureFixesv0.4.4Working implementation