From 936a524263b90071d601b09a63f3c86117769b61 Mon Sep 17 00:00:00 2001 From: Mike Bayer <mike_mp@zzzcomputing.com> Date: Thu, 8 Mar 2012 16:02:05 -0800 Subject: [PATCH] - [bug] Fixed endless recursion bug when nesting multiple def-calls with content. Thanks to Jeff Dairiki. [ticket:186] --- CHANGES | 4 ++++ mako/codegen.py | 8 ++++---- mako/runtime.py | 6 +++++- test/test_call.py | 11 +++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 4783699..2d3dabe 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,10 @@ to filehandles being implicitly closed. [ticket:182] +- [bug] Fixed endless recursion bug when + nesting multiple def-calls with content. + Thanks to Jeff Dairiki. [ticket:186] + 0.6.2 - [bug] The ${{"foo":"bar"}} parsing issue is fixed!! The legendary Eevee has slain the dragon! diff --git a/mako/codegen.py b/mako/codegen.py index 2e15124..704330c 100644 --- a/mako/codegen.py +++ b/mako/codegen.py @@ -231,7 +231,8 @@ class _GenerateRenderMethod(object): self.printer.writelines( "def %s(%s):" % (name, ','.join(args)), - "context.caller_stack._push_frame()", + # push new frame, assign current frame to __M_caller + "__M_caller = context.caller_stack._push_frame()", "try:" ) if buffered or filtered or cached: @@ -516,7 +517,8 @@ class _GenerateRenderMethod(object): buffered = eval(node.attributes.get('buffered', 'False')) cached = eval(node.attributes.get('cached', 'False')) self.printer.writelines( - "context.caller_stack._push_frame()", + # push new frame, assign current frame to __M_caller + "__M_caller = context.caller_stack._push_frame()", "try:" ) if buffered or filtered or cached: @@ -848,8 +850,6 @@ class _GenerateRenderMethod(object): ) self.printer.writelines( - # get local reference to current caller, if any - "__M_caller = context.caller_stack._get_caller()", # push on caller for nested call "context.caller_stack.nextcaller = " "runtime.Namespace('caller', context, callables=ccall(__M_caller))", diff --git a/mako/runtime.py b/mako/runtime.py index 65c03e1..b56fa67 100644 --- a/mako/runtime.py +++ b/mako/runtime.py @@ -158,12 +158,16 @@ class CallerStack(list): def __nonzero__(self): return self._get_caller() and True or False def _get_caller(self): + # this method can be removed once + # codegen MAGIC_NUMBER moves past 7 return self[-1] def __getattr__(self, key): return getattr(self._get_caller(), key) def _push_frame(self): - self.append(self.nextcaller or None) + frame = self.nextcaller or None + self.append(frame) self.nextcaller = None + return frame def _pop_frame(self): self.nextcaller = self.pop() diff --git a/test/test_call.py b/test/test_call.py index 5f13e95..0bb6079 100644 --- a/test/test_call.py +++ b/test/test_call.py @@ -385,6 +385,17 @@ class CallTest(TemplateTest): """) assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call"] + def test_composed_def(self): + t = Template(""" + <%def name="f()"><f>${caller.body()}</f></%def> + <%def name="g()"><g>${caller.body()}</g></%def> + <%def name="fg()"> + <%self:f><%self:g>${caller.body()}</%self:g></%self:f> + </%def> + <%self:fg>fgbody</%self:fg> + """) + assert result_lines(t.render()) == ['<f><g>fgbody</g></f>'] + def test_regular_defs(self): t = Template(""" <%! -- GitLab