summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Whittaker <carl.whittaker@hogarthww.com>2011-01-13 19:36:33 +0000
committerCarl Whittaker <carl.whittaker@hogarthww.com>2011-01-13 19:36:33 +0000
commitbc5d0e2700506d1fe7fa87a0e345f84ea42bc8aa (patch)
tree85816fc610de31a232b004d7cbbe568600c5482c
parent69406c082340f4017bb86e066ce6ae708a5ac8f0 (diff)
downloadpystache-bc5d0e2700506d1fe7fa87a0e345f84ea42bc8aa.tar.gz
Fixed accessing mixed nested context objects. BOOM!
-rw-r--r--examples/partial_in_partial.mustache1
-rw-r--r--examples/template_partial.py5
-rw-r--r--pystache/template.py39
-rw-r--r--tests/test_examples.py6
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()