defunkt / pystache Goto Github PK
View Code? Open in Web Editor NEWMustache in Python
Home Page: http://mustache.github.com/
License: MIT License
Mustache in Python
Home Page: http://mustache.github.com/
License: MIT License
Also, they should pass running nosetests --with-doctest
.
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:
https://github.com/mustache/spec/blob/master/specs/sections.yml#L123
>>> import pystache
>>> pystache.render("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |", {bool:True})
'| A D E |'
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.
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).
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:
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.
Make Renderer.render()
more robust. Currently, it can break if load_template returns a non-unicode string with non-ascii characters. This is related to issue #10.
This issue is copied from issue #31 so that the two issues it raises can be handled and discussed separately.
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 :)
The Loader constructor should accept a decode_errors keyword argument like the Renderer class does. It already supports an encoding argument.
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!'
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}}')
The Template class should support encoding
and errors
attributes (suitably named) that can be passed to unicode()
and markupsafe.Markup()
when converting Python str
's to unicode.
This is towards issue #10.
The constructor Template.__init__()
should accept an optional escape
function argument instead of the boolean disable_escape
. This is more natural.
Examples:
lambda s: s
.lambda s: cgi.escape(s, True)
.markupsafe.escape()
.Does someone want to take over? I'm not using Pystache in any projects.
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.
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.
We should escape double-quotation marks by default.
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(...)
Currently, pystache.loader.Loader.load_template() adds a dot no matter what :
file_name = template_name + '.' + self.template_extension
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.
These two expressions should produce identical results, but don't:
>>> pystache.render('{{=$ $=}} {{hugged}} ', {})
' {{hugged}} '
>>> pystache.render('{{=$ $=}} {{hugged}} $={{ }}=$', {})
' '
>>>
Is anyone actively maintaining this repo anymore? How do we go about reviving it?
<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,.
Passing **kwargs
to Template.__init__()
with no context raises an exception:
template = Template(foo="bar")
Passing **kwargs
to Template.__init__()
modifies the passed context:
context = {}
template = Template(context=context, foo="bar")
We should make a copy of the context inside Template.__init__()
like we do in pystache.render()
.
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.
It's better to fail fast.
View class always executes callable variables, it doesn't matter if it's a view's method or a lambda in the context dictionary.
Bug can be spotted by running the code in the following gist:
http://gist.github.com/522505
I wrote a test and code to fix it, as you can see in this compare view:
http://github.com/rafaelcv/pystache/compare/defunkt:49c34b...view_callable_bug
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).
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.
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.
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):
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.
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"]
}
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):
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".
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.
In Template.render_tag
, Pystache converts the value about to be rendered into a string using str()
. If that value is a Unicode string containing any non-ASCII characters, rendering will fail with a UnicodeEncodeError
.
enaeseth/pystache@f123343 is one way of working around this (really quite annoying) problem.
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.
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.
import pystache
pystache.render('{{test}}', {'test':'Hello {{world}}'})
Outputs Hello
while I'd expect Hello {{world}}
. which is what http://mustache.github.com/#demo outputs.
Also means the following throws an error
import pystache
pystache.render('{{test}}', {'test':'Hello {{#world}}'})
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><p><p><p><p><p><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><p><p><p><p><p><p><p><p>')
The error does not occur at tag 3.1. Just thought I'd make you guys aware of this.
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.
We need a mechanism to allow testing of the Template class with markupsafe both enabled and not enabled.
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: '#'
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.
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.