diff options
author | Carl Whittaker <carl.whittaker@hogarthww.com> | 2011-01-13 19:36:33 +0000 |
---|---|---|
committer | Carl Whittaker <carl.whittaker@hogarthww.com> | 2011-01-13 19:36:33 +0000 |
commit | bc5d0e2700506d1fe7fa87a0e345f84ea42bc8aa (patch) | |
tree | 85816fc610de31a232b004d7cbbe568600c5482c | |
parent | 69406c082340f4017bb86e066ce6ae708a5ac8f0 (diff) | |
download | pystache-bc5d0e2700506d1fe7fa87a0e345f84ea42bc8aa.tar.gz |
Fixed accessing mixed nested context objects. BOOM!
-rw-r--r-- | examples/partial_in_partial.mustache | 1 | ||||
-rw-r--r-- | examples/template_partial.py | 5 | ||||
-rw-r--r-- | pystache/template.py | 39 | ||||
-rw-r--r-- | tests/test_examples.py | 6 |
4 files changed, 33 insertions, 18 deletions
diff --git a/examples/partial_in_partial.mustache b/examples/partial_in_partial.mustache new file mode 100644 index 0000000..c61ceb1 --- /dev/null +++ b/examples/partial_in_partial.mustache @@ -0,0 +1 @@ +{{>simple}}
\ No newline at end of file diff --git a/examples/template_partial.py b/examples/template_partial.py index 29e9c5f..651cbe5 100644 --- a/examples/template_partial.py +++ b/examples/template_partial.py @@ -10,4 +10,7 @@ class TemplatePartial(pystache.View): return '-' * len(self.title()) def looping(self): - return [{'item': 'one'}, {'item': 'two'}, {'item': 'three'}]
\ No newline at end of file + return [{'item': 'one'}, {'item': 'two'}, {'item': 'three'}] + + def thing(self): + return self['prop']
\ No newline at end of file diff --git a/pystache/template.py b/pystache/template.py index 282b22d..1721665 100644 --- a/pystache/template.py +++ b/pystache/template.py @@ -19,16 +19,21 @@ def modifier(symbol): return func return set_modifier -def get_or_attr(obj, name, default=None): - try: - return obj[name] - except KeyError: +def get_or_attr(context_list, name, default=None): + if not context_list: return default - except: + + for obj in context_list: try: - return getattr(obj, name) - except AttributeError: - return default + return obj[name] + except KeyError: + pass + except: + try: + return getattr(obj, name) + except AttributeError: + pass + return default class Template(object): @@ -47,7 +52,7 @@ class Template(object): context.update(kwargs) self.view = context if isinstance(context, View) else View(context=context) - + self.context_list = [self.view] self._compile_regexps() def _compile_regexps(self): @@ -71,7 +76,7 @@ class Template(object): section, section_name, inner = match.group(0, 1, 2) section_name = section_name.strip() - it = get_or_attr(view, section_name, None) + it = get_or_attr(self.context_list, section_name, None) replacer = '' # Callable @@ -84,7 +89,7 @@ class Template(object): # Lists elif it and hasattr(it, '__iter__'): if section[2] != '^': - replacer = self._render_list(inner, it) + replacer = self._render_list(inner, it) # Falsey and Negated or Truthy and Not Negated elif (not it and section[2] == '^') or (it and section[2] != '^'): replacer = inner @@ -108,11 +113,11 @@ class Template(object): return template def _render_dictionary(self, template, context): - original_context = copy.copy(self.view.context) - self.view.context.update(context) - out = Template(template, self.view).render() - self.view.context = original_context - + template = Template(template, self.view) + self.context_list.insert(0, context) + template.context_list = self.context_list + out = template.render() + self.context_list.pop(0) return out def _render_list(self, template, listing): @@ -124,7 +129,7 @@ class Template(object): @modifier(None) def _render_tag(self, tag_name, view): - raw = get_or_attr(view, tag_name, '') + raw = get_or_attr(self.context_list, tag_name, '') # For methods with no return value if not raw and raw is not 0: diff --git a/tests/test_examples.py b/tests/test_examples.py index 8b3624b..0b405f1 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -76,5 +76,11 @@ Again, Welcome! view.template = '{{#herp}}{{#derp}}{{nested_context_in_view}}{{/derp}}{{/herp}}' self.assertEquals(view.render(), 'it works!') + def test_partial_in_partial_has_access_to_grand_parent_context(self): + view = TemplatePartial() + view.context = {'prop': 'derp'} + view.template = '''{{>partial_in_partial}}''' + self.assertEquals(view.render(), 'Hi derp!') + if __name__ == '__main__': unittest.main() |