diff --git a/pystache/__init__.py b/pystache/__init__.py index 4cf24344..4318d2dd 100644 --- a/pystache/__init__.py +++ b/pystache/__init__.py @@ -10,4 +10,4 @@ __all__ = ['parse', 'render', 'Renderer', 'TemplateSpec'] -__version__ = '0.5.4' # Also change in setup.py. +__version__ = '0.5.4a' # Also change in setup.py. diff --git a/pystache/context.py b/pystache/context.py index 67159160..0a01dd53 100644 --- a/pystache/context.py +++ b/pystache/context.py @@ -66,6 +66,10 @@ def _get_value(context, key): # See the following issue for implementation ideas: # http://bugs.python.org/issue7559 pass + except UnicodeEncodeError: + # we managed to get a tag that has unicode in it, and getattr() + # doesn't support that + pass else: # TODO: consider using EAFP here instead. # http://docs.python.org/glossary.html#term-eafp diff --git a/pystache/parser.py b/pystache/parser.py index 9a4fba23..32f06792 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -18,7 +18,7 @@ # TODO: add some unit tests for this. # TODO: add a test case that checks for spurious spaces. # TODO: add test cases for delimiters. -def parse(template, delimiters=None): +def parse(template, delimiters=None, liberal_sections=False): """ Parse a unicode template string and return a ParsedTemplate instance. @@ -37,7 +37,7 @@ def parse(template, delimiters=None): """ if type(template) is not unicode: raise Exception("Template is not unicode: %s" % type(template)) - parser = _Parser(delimiters) + parser = _Parser(delimiters, liberal_sections=liberal_sections) return parser.parse(template) @@ -147,7 +147,8 @@ def __repr__(self): def render(self, engine, context): template = engine.resolve_partial(self.key) # Indent before rendering. - template = re.sub(NON_BLANK_RE, self.indent + ur'\1', template) + if not isinstance(template, ParsedTemplate): + template = re.sub(NON_BLANK_RE, self.indent + ur'\1', template) return engine.render(template, context) @@ -226,11 +227,12 @@ class _Parser(object): _delimiters = None _template_re = None - def __init__(self, delimiters=None): + def __init__(self, delimiters=None, liberal_sections=False): if delimiters is None: delimiters = defaults.DELIMITERS self._delimiters = delimiters + self.liberal_sections = liberal_sections def _compile_delimiters(self): self._template_re = _compile_template_re(self._delimiters) @@ -316,9 +318,15 @@ def parse(self, template): continue if tag_type == '/': - if tag_key != section_key: - raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) - + if tag_key is not None and section_key is not None and tag_key.lower() != section_key.lower(): + parsed_section_key = section_key.split("|")[0] + if parsed_section_key: + parsed_section_key = parsed_section_key.strip() + if tag_key.lower() != parsed_section_key.lower(): + if not self.liberal_sections: + raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key)) + else: + tag_key = parsed_section_key # Restore previous state with newly found section data. parsed_section = parsed_template diff --git a/pystache/renderengine.py b/pystache/renderengine.py index c797b176..eafec24a 100644 --- a/pystache/renderengine.py +++ b/pystache/renderengine.py @@ -9,6 +9,7 @@ from pystache.common import is_string from pystache.parser import parse +from pystache.parsed import ParsedTemplate def context_get(stack, name): @@ -176,6 +177,9 @@ def render(self, template, context_stack, delimiters=None): context_stack: a ContextStack instance. """ - parsed_template = parse(template, delimiters) + if isinstance(template, ParsedTemplate): + parsed_template = template + else: + parsed_template = parse(template, delimiters) return parsed_template.render(self, context_stack) diff --git a/pystache/renderer.py b/pystache/renderer.py index ff6a90c6..a913da65 100644 --- a/pystache/renderer.py +++ b/pystache/renderer.py @@ -265,7 +265,9 @@ def load_partial(name): raise TemplateNotFoundError("Name %s not found in partials: %s" % (repr(name), type(partials))) - # RenderEngine requires that the return value be unicode. + # RenderEngine requires that the return value be unicode or a parsed template. + if isinstance(template, ParsedTemplate): + return template return self._to_unicode_hard(template) return load_partial diff --git a/pystache/tests/test_renderer.py b/pystache/tests/test_renderer.py index 0dbe0d99..9d9b7934 100644 --- a/pystache/tests/test_renderer.py +++ b/pystache/tests/test_renderer.py @@ -12,6 +12,7 @@ from examples.simple import Simple from pystache import Renderer +from pystache.parser import parse from pystache import TemplateSpec from pystache.common import TemplateNotFoundError from pystache.context import ContextStack, KeyNotFoundError @@ -368,6 +369,16 @@ def test_make_resolve_partial__unicode(self): # TypeError: decoding Unicode is not supported self.assertEqual(resolve_partial("partial"), "foo") + def test_make_resolve_partial__parsed(self): + """ + Test _make_resolve_partial__parsed(): that we can take ParsedTemplates as partials + + """ + partials = {"partial": parse(u"Hello, {{person}}")} + renderer = Renderer(partials=partials) + actual = renderer.render(u"{{>partial}}", {"person": "foo"}) + self.assertString(actual, u"Hello, foo") + def test_render_name(self): """Test the render_name() method.""" data_dir = get_data_path() diff --git a/setup.py b/setup.py index 0d99aae8..0efd3a49 100644 --- a/setup.py +++ b/setup.py @@ -112,7 +112,7 @@ setup = dist.setup -VERSION = '0.5.4' # Also change in pystache/__init__.py. +VERSION = '0.5.4a' # Also change in pystache/__init__.py. FILE_ENCODING = 'utf-8'