Giter Site home page Giter Site logo

pystache's Introduction

Pystache

Pystache is a Python implementation of Mustache. Mustache is a framework-agnostic, logic-free templating system inspired by ctemplate and et. Like ctemplate, Mustache "emphasizes separating logic from presentation: it is impossible to embed application logic in this template language."

The mustache(5) man page provides a good introduction to Mustache's syntax. For a more complete (and more current) description of Mustache's behavior, see the official Mustache spec.

Pystache is semantically versioned and can be found on PyPI. This version of Pystache passes all tests in version 1.1.2 of the spec.

Requirements

Pystache is tested with--

  • Python 2.4 (requires simplejson version 2.0.9 or earlier)
  • Python 2.5 (requires simplejson)
  • Python 2.6
  • Python 2.7
  • Python 3.1
  • Python 3.2
  • Python 3.3
  • PyPy

Distribute (the setuptools fork) is recommended over setuptools, and is required in some cases (e.g. for Python 3 support). If you use pip, you probably already satisfy this requirement.

JSON support is needed only for the command-line interface and to run the spec tests. We require simplejson for earlier versions of Python since Python's json module was added in Python 2.6.

For Python 2.4 we require an earlier version of simplejson since simplejson stopped officially supporting Python 2.4 in simplejson version 2.1.0. Earlier versions of simplejson can be installed manually, as follows:

pip install 'simplejson<2.1.0'

Official support for Python 2.4 will end with Pystache version 0.6.0.

Install It

pip install pystache

And test it--

pystache-test

To install and test from source (e.g. from GitHub), see the Develop section.

Use It

>>> import pystache
>>> print pystache.render('Hi {{person}}!', {'person': 'Mom'})
Hi Mom!

You can also create dedicated view classes to hold your view logic.

Here's your view class (in .../examples/readme.py):

class SayHello(object):
    def to(self):
        return "Pizza"

Instantiating like so:

>>> from pystache.tests.examples.readme import SayHello
>>> hello = SayHello()

Then your template, say_hello.mustache (by default in the same directory as your class definition):

Hello, {{to}}!

Pull it together:

>>> renderer = pystache.Renderer()
>>> print renderer.render(hello)
Hello, Pizza!

For greater control over rendering (e.g. to specify a custom template directory), use the Renderer class like above. One can pass attributes to the Renderer class constructor or set them on a Renderer instance. To customize template loading on a per-view basis, subclass TemplateSpec. See the docstrings of the Renderer class and TemplateSpec class for more information.

You can also pre-parse a template:

>>> parsed = pystache.parse(u"Hey {{#who}}{{.}}!{{/who}}")
>>> print parsed
[u'Hey ', _SectionNode(key=u'who', index_begin=12, index_end=18, parsed=[_EscapeNode(key=u'.'), u'!'])]

And then:

>>> print renderer.render(parsed, {'who': 'Pops'})
Hey Pops!
>>> print renderer.render(parsed, {'who': 'you'})
Hey you!

Python 3

Pystache has supported Python 3 since version 0.5.1. Pystache behaves slightly differently between Python 2 and 3, as follows:

  • In Python 2, the default html-escape function cgi.escape() does not escape single quotes. In Python 3, the default escape function html.escape() does escape single quotes.
  • In both Python 2 and 3, the string and file encodings default to sys.getdefaultencoding(). However, this function can return different values under Python 2 and 3, even when run from the same system. Check your own system for the behavior on your system, or do not rely on the defaults by passing in the encodings explicitly (e.g. to the Renderer class).

Unicode

This section describes how Pystache handles unicode, strings, and encodings.

Internally, Pystache uses only unicode strings (str in Python 3 and unicode in Python 2). For input, Pystache accepts both unicode strings and byte strings (bytes in Python 3 and str in Python 2). For output, Pystache's template rendering methods return only unicode.

Pystache's Renderer class supports a number of attributes to control how Pystache converts byte strings to unicode on input. These include the file_encoding, string_encoding, and decode_errors attributes.

The file_encoding attribute is the encoding the renderer uses to convert to unicode any files read from the file system. Similarly, string_encoding is the encoding the renderer uses to convert any other byte strings encountered during the rendering process into unicode (e.g. context values that are encoded byte strings).

The decode_errors attribute is what the renderer passes as the errors argument to Python's built-in unicode-decoding function (str() in Python 3 and unicode() in Python 2). The valid values for this argument are strict, ignore, and replace.

Each of these attributes can be set via the Renderer class's constructor using a keyword argument of the same name. See the Renderer class's docstrings for further details. In addition, the file_encoding attribute can be controlled on a per-view basis by subclassing the TemplateSpec class. When not specified explicitly, these attributes default to values set in Pystache's defaults module.

Develop

To test from a source distribution (without installing)--

python test_pystache.py

To test Pystache with multiple versions of Python (with a single command!), you can use tox:

pip install 'virtualenv<1.8'  # Version 1.8 dropped support for Python 2.4.
pip install 'tox<1.4'  # Version 1.4 dropped support for Python 2.4.
tox

If you do not have all Python versions listed in tox.ini--

tox -e py26,py32  # for example

The source distribution tests also include doctests and tests from the Mustache spec. To include tests from the Mustache spec in your test runs:

git submodule init
git submodule update

The test harness parses the spec's (more human-readable) yaml files if PyYAML is present. Otherwise, it parses the json files. To install PyYAML--

pip install pyyaml

To run a subset of the tests, you can use nose:

pip install nose
nosetests --tests pystache/tests/test_context.py:GetValueTests.test_dictionary__key_present

Using Python 3 with Pystache from source

Pystache is written in Python 2 and must be converted to Python 3 prior to using it with Python 3. The installation process (and tox) do this automatically.

To convert the code to Python 3 manually (while using Python 3)--

python setup.py build

This writes the converted code to a subdirectory called build. By design, Python 3 builds cannot be created from Python 2.

To convert the code without using setup.py, you can use 2to3 as follows (two steps)--

2to3 --write --nobackups --no-diffs --doctests_only pystache
2to3 --write --nobackups --no-diffs pystache

This converts the code (and doctests) in place.

To import pystache from a source distribution while using Python 3, be sure that you are importing from a directory containing a converted version of the code (e.g. from the build directory after converting), and not from the original (unconverted) source directory. Otherwise, you will get a syntax error. You can help prevent this by not running the Python IDE from the project directory when importing Pystache while using Python 3.

Mailing List

There is a mailing list. Note that there is a bit of a delay between posting a message and seeing it appear in the mailing list archive.

Credits

>>> context = { 'author': 'Chris Wanstrath', 'maintainer': 'Chris Jerdonek' }
>>> print pystache.render("Author: {{author}}\nMaintainer: {{maintainer}}", context)
Author: Chris Wanstrath
Maintainer: Chris Jerdonek

Pystache logo by David Phillips is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

pystache's People

Contributors

adamv avatar alex avatar arkany avatar bennoleslie avatar carlmw avatar cjerdonek avatar dbr avatar defunkt avatar dinoboff avatar djl avatar ericflo avatar greengremlin avatar heliodor avatar io41 avatar jakearchibald avatar joshthecoder avatar kevincarrogan avatar lambacck avatar lucasb-eyer avatar markpasc avatar mikeocool avatar msabramo avatar pib avatar pombredanne avatar pvande avatar rbp avatar talos avatar zacharyvoase avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pystache's Issues

Support python2.5 on Google App Engine

I knew the requirement is python2.6, but it's better to support python2.5. It will be more useful for Google App Engine developers.
It only few lines change, I will attach the code later.

TemplateSpec should let one specify the template file path

It seems like the View class should allow one to specify the path to the view's template file directly.

Currently, the only way to do this is to strip the extension from the file name and set this as the View instance's template_name, and then include the file's directory in a list of template directories and set this as the View instance's template_path, which seems more awkward than it needs to be.

Of course, the other way is to load the template yourself and pass it as a string, but this is also less convenient.

Related to this, the View class's template_path attribute would probably be better named something like template_dirs or template_search_dirs. Indeed, the View class's get_template() method passes self.template_path--

self.template = Loader().load_template(template_name, self.template_path, encoding=self.template_encoding, extension=self.template_extension)

as Loader.load_template()'s template_dirs parameter:

def load_template(self, template_name, template_dirs=None, encoding=None, extension=None):

Remove the context parameter from Template.__init__()

Rather than passing the context to render to Template.__init__():

template = Template(template, context, **kwargs)
rendered = template.render()

I think we should pass the context to render to Template.render():

template = Template(template)
rendered = template.render(context, **kwargs)

This is conceptually clearer because the context to render is distinct from the template itself.

This also has at least a couple advantages from an API perspective:

(1) It lets you render multiple contexts with the same template:

template = Template(template)
rendered1 = template.render(context1)
rendered2 = template.render(context2)

(2) It also promotes a clean separation between Template options and the context **kwargs. For example, we could do this:

template = Template(template, **options)
rendered = template.render(context, **kwargs)

Passing both template options and context **kwargs to Template.__init__() leads to the situation where adding a new Template option as a keyword argument always breaks backwards compatiblity (by potentially conflicting with context **kwargs that are already out in the wild).

Whitespace issues

<ul>
{{#link}}
    <li><a href="{{url}}">{{text}}</a></li>
{{/link}}
</ul>

Its removing the 'newlineness' and the indentation (\t) of the <li>

Thanks for any help :) and thankyou very much for porting it in the first place,.

Add option to disable html escape

It would be nice to be able to generate raw text output for text emails for example. An option on the View to disable html escape altogether for example.

multiline comments not working

From: http://mustache.github.com/mustache.5.html

Comments may contain newlines.

Here is my testcase:

import pystache
print pystache.render('foo{{! baz }}bar')
print pystache.render('foo{{! \nbaz }}bar')

Expected output:

foobar
foobar

Current output:

foobar
foo{{! 
baz }}bar

Sugested fix:

--- a/pystache/template.py
+++ b/pystache/template.py
@@ -66,7 +66,7 @@ class Template(object):
         self.section_re = re.compile(section % tags, re.M|re.S)

         tag = r"%(otag)s(#|=|&|!|>|\{)?(.+?)\1?%(ctag)s+"
-        self.tag_re = re.compile(tag % tags)
+        self.tag_re = re.compile(tag % tags,re.DOTALL)

     def _render_sections(self, template, view):
         while True:

Changing delimiters back is retroactive

These two expressions should produce identical results, but don't:

>>> pystache.render('{{=$ $=}} {{hugged}} ', {})
' {{hugged}} '
>>> pystache.render('{{=$ $=}} {{hugged}} $={{ }}=$', {})
'  '
>>> 

Output of callables treated as template code

This is caused by _render_tags operating on the output of _render_sections

Failing test:

def test_tag_in_labda_output(self):
    template = '{{#test}}Blah{{/test}}'
    context = {
        'test': lambda x: '{{hello}}'
    }
    ret = pystache.render(template, context)
    self.assertEquals(ret, '{{hello}}')

Change Renderer to accept a loader implementing get()

Changing Renderer.__init__() from accepting a load_template function to accepting a loader with a get() method will simplify the API a bit. This will also make loading partials from a dictionary easier (and the same as passing a loader), since dictionaries implement get():

>>> partials = {'partial': 'Hello, {{thing}}!'}
>>> renderer = Renderer(loader=partials)
>>> renderer.render('{{>partial}}', {'thing': 'world'})
u'Hello, world!'

RenderEngine should operate only on unicode strings

When markupsafe is importable, RenderEngine mixes operations between Markup strings and unicode strings. This can (and has) lead to subtle double-escaping and related bugs, etc. For clarity, RenderEngine should probably operate exclusively on unicode strings. The conversion to Markup can take place afterwards.

We should also increase our test coverage to check for double-escaping and related issues when markupsafe is enabled.

mustache(5) documentation: clarify that non-false values inherit parent context

The mustache(5) documentation isn't always explicit as to when the parent context should be inherited, though this seems to be implied in parts. To reduce ambiguity, I think it would help to be more explicit on this point.

I don't know all the parts that need clarification, but here is one:

**Non-False Values**

When the value is non-false but not a list, it will be used as the
context for a single rendering of the block.

If my understanding is right, I think something like the following would be clearer:

**Non-False Values**

When the value is non-false but not a list, it will be used as the
context for a single rendering of the block.  This context should
also fall back to the parent context.

Thanks.

Silly to string conversion forcing

Template's render_unescaped method trying to convert value to string. It breaks when value is not string but unicode or some object convertable to unicode. In the same time render_tag converts value to unicode. I think there is consistency needed.

Patch:

diff --git a/pystache/template.py b/pystache/template.py
index c942cd7..690710e 100644
--- a/pystache/template.py
+++ b/pystache/template.py
@@ -110,7 +110,7 @@ class Template(object):
     @modifier('{')
     def render_unescaped(self, tag_name=None, context=None):
         """Render a tag without escaping it."""
-        return str(context.get(tag_name, ''))
+        return unicode(context.get(tag_name, ''))

     @modifier('>')
     def render_partial(self, tag_name=None, context=None):

maintainers?

Is anyone actively maintaining this repo anymore? How do we go about reviving it?

Create a RenderEngine class (make Template class smaller)

We could simplify the code a bit by creating a RenderEngine class to house the rendering logic separate from the Template class.

This class would be used internally by the Template class and would operate only on unicode strings and Context instances. The end-user wouldn't interact with the RenderEngine class directly. The Template class would serve for now as the end-user API for the RenderEngine class and would do the necessary pre-processing (e.g. creating a Context instance) and post-processing (e.g. calling result.encode()).

This will also make it easier for us to focus on the rendering logic itself, because it will be more separate from less related considerations (separation of concerns).

Template loading case sensitive issue

I noticed this issue when I went to run the nose tests on linux. Pystache attempts to load the template using the View's class name, which is usually capitalized. This creates a problem on case sensitive OS's (like linux) and it will complain about not finding the template file (which in the tests case is called simple.mustache, not Simple.mustache).

Here's a small fix that lower cases the class name before attempting to load the template.

http://gist.github.com/226741

Template path not propagated when rendering a partial inside a section

Related to issue #8, if you put a partial within a section, it won't be able to find the template if you are using 'template_path' in your view.

outer.mustache

{{#somevalues}}
{{> rendervalues}}}
{{/somevalues

rendervalues.mustache:

{{name}}

If you set template_path in your view for outer.mustache, that template_path is not used to find rendervalues.mustache because though we are using a View, the values aren't 'inherited'.

Bug is in here:

@modifier('>')
def render_partial(self, tag_name=None, context=None):
    """Renders a partial within the current context."""
    # Import view here to avoid import loop
    from pystache.view import View

    view = View(context=context)
    view.template_name = tag_name

    return view.render()

In the above, the view 'settings' would be correctly copied over if context was a view, but since this is while rendering a section, context is something else.

The real issue is the strange relationship between templates and views. As the comment above indicates, there is a 'loop' between views and templates... Really it's a bad case of tight coupling. Views need templates, and templates need views.

Template.render() should convert templates to unicode

This doesn't work yet (passing Template() an output encoding and a non-unicode template with non-ascii characters):

template = Template("déf", default_encoding='utf-8', output_encoding="utf-8")
template.render()

This is towards issue #10.

custom delimeter in sections do not work

this does not work:
>>> pystache.render('{{=[[ ]]=}} hi [[#person]]person[[/person]]',{'person':'jack'})
Traceback (most recent call last):
File "", line 1, in
File "pystache/init.py", line 7, in render
return Template(template, context).render()
File "pystache/template.py", line 57, in render
result = self.render_tags(template, context)
File "pystache/template.py", line 113, in render_tags
func = modifiers[tag_type]
KeyError: '#'

Encoding issue

Pystache doesn't work with strings encoded in non ascii encoding.

There is template_encoding variable that permits write templates in any encoding but there isn't such variable for strings generated by application.

In template.py file, in render_tag and render_unescaped functions there is unicode() function called without second parameter - the default encoding (ascii) is assumed even if string passed to it is UTF-8 encoded.

New Maintainer?

Does someone want to take over? I'm not using Pystache in any projects.

Rename Template class to Renderer class

The Template class is really more of a "rendering" class for storing all of the options on how to render a template string.

The attribute self.template is only used once in the class, and that's in the Template.render() method when it passes self.template to the RenderEngine. So why not just pass the template string directly to render()?

This will make the API much simpler going forward. For example, this will let us eventually pass View instances to render() (in addition to template strings), so that we won't have to repeat all of the rendering options a second time in the View class.

Pystache does not render 0

The last commit made to Pystache (e38a953) stopped rendering None and False as 'None' and 'False' in templates. This is good, but Pystache now refuses to render all values that evaluate to false, which unfortunately includes 0.

A fix for this (and associated test) can be found at enaeseth/pystache@6e5d57c.

Template class should not depend on the View class

This is an issue placeholder for the milestone "Template class should not depend on the View class" -- for discussion purposes and so we can reference it.

It doesn't seem like GitHub lets one easily link to or discuss a milestone directly.

View class should not "own" the context

It seems like View instances should not "own" the rendering context (as they currently do via View.context_list).

The context stack is part of the state used during the rendering process, and so would be more appropriately owned and managed by whatever is doing the rendering. (Currently Template instances manage the rendering, for example in the Template._render_dictionary() method by pushing and popping the context stack.)

Addressing this issue will help simplify the View class and better define separations of concern.

can't see values in 'outer' context when inside a loop

I've got a dead simple template and data structure.

....amended original comment with inline code and templates,
as it looked godawful....

Upshot is: Ruby Mustaches seems to DTRT, Pystache doesn't. Really hope it's a pystache bug :)

{{#x}}{{#x}}{{/x}}{{/x}} breaks

You cannot work with objects such as the following due to pystache's reliance on regular expressions instead of a grammar:

{documents: [{name:1, children:[{name: 2, children:[...]}]}]}

Here's a test case that causes pystache to raise an exception:

http://pastebin.com/4eAYfyKD

not correctly handling 'Non-False Values'

pystache doesn't implement the behavior for 'Non-False Values' described in the mustache 'spec':

[1]http://mustache.github.com/mustache.5.html

Example from spec page:

Template:

{{#person?}}
Hi {{name}}!
{{/person?}}
Hash:

{
"person?": { "name": "Jon" }
}
Output:

Hi Jon!

pystache iterates over the keys of the {"name": "Jon"} object -- this gives an error as the string object "name" has no get lookup method. The behavior is the same as one would get by passing in this context:

{
"person?": ["name"]
}

Trunk sometimes escapes list blocks for no reason

Every list block except the first one in the template has its contents escaped.

>>> pystache.render("<p>{{#this}}<p>{{/this}}<p>{{#that}}<p>{{/that}}<p>{{#other}}<p>{{/other}}<p>", {'this':[1,2], 'that':[1,2], 'other':[1,2]})
Markup(u'<p><p><p><p>&lt;p&gt;&lt;p&gt;<p>&lt;p&gt;&lt;p&gt;<p>')

You can't get the error by repeating the same block though: if it renders unescaped the first time, it will do the same thing the second time, and visa versa.

>>> pystache.render("<p>{{#this}}<p>{{/this}}<p>{{#that}}<p>{{/that}}<p>{{#this}}<p>{{/this}}<p>{{#that}}<p>{{/that}}", {'this':[1,2], 'that':[1,2]})
Markup(u'<p><p><p><p>&lt;p&gt;&lt;p&gt;<p><p><p><p>&lt;p&gt;&lt;p&gt;')

The error does not occur at tag 3.1. Just thought I'd make you guys aware of this.

Report spec compliance

From the Mustache spec:

Mustache implementations SHOULD report the most recent version of the spec (major and minor version numbers). If an implementation has support for any optional modules, they SHOULD indicate so with a remark attached to the version number (e.g. "vX.Y, including lambdas" or "v.X.Y+λ"). It is RECOMMENDED that implementations not supporting at least v1.0.0 of this spec refer to themselves as "Mustache-like", or "Mustache-inspired".

Remove pystache.Pystache object?

from pystache import Pystache
Pystache.render(...)

..seems a rather roundabout way of doing things, why not change __init__.py to..

from pystache.template import Template

def render(template, context={}):
    return Template(template, context).render()

So you can do..

import pystache
pystache.render(...)

Mustache(5) example not working

Template:

{{#person?}}
Hi {{name}}!
{{/person?}}

Dictinary:
{
"person?": { "name": "Jon" }
}

Crashes -> this also does not work in the javascript version, I will submit a bug there also.

pip install breaks

when installing pystache via pip, setup.py breaks when trying to open README.rst. It looks like the 0.3.0 package on pypi doesn't include the README.rst in the tar.gz file.

Support View attributes in Renderer class

The Renderer class should support the same template-related attributes that the View class supports (e.g. template_encoding and template_extension) -- e.g. when creating a default Loader. This will bring template-rendering to parity with view-rendering.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.