diff --git a/CHANGES b/CHANGES index 7036ee9d58441b9423a076af1036a4542d77d7b6..23a9600c13ead4c5c49e45b6d4bb0b9bfc963f3e 100644 --- a/CHANGES +++ b/CHANGES @@ -50,7 +50,10 @@ - Bugfixes: - can now use most names from __builtins__ as variable names without explicit declaration (i.e. 'id', - 'exception', 'range', etc.) [ticket:83] + 'exception', 'range', etc.) [ticket:83] [ticket:84] + + - can also use builtin names as local variable names + (i.e. dict, locals) (came from fix for [ticket:84]) - fixed bug in python generation when variable names are used with identifiers like "else", "finally", etc. diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py index 3600b3d25bef7a5728c7670fd322fa157f39560e..46dc502de92a02106ebd00813897f9ed3ac685d0 100644 --- a/lib/mako/codegen.py +++ b/lib/mako/codegen.py @@ -118,6 +118,8 @@ class _GenerateRenderMethod(object): self.printer.writeline("from mako import runtime, filters, cache") self.printer.writeline("UNDEFINED = runtime.UNDEFINED") + self.printer.writeline("__M_dict_builtin = dict") + self.printer.writeline("__M_locals_builtin = locals") self.printer.writeline("_magic_number = %s" % repr(MAGIC_NUMBER)) self.printer.writeline("_modified_time = %s" % repr(time.time())) self.printer.writeline("_template_filename=%s" % repr(self.compiler.filename)) @@ -171,7 +173,7 @@ class _GenerateRenderMethod(object): self.identifier_stack[-1].argument_declared.add('pageargs') if not self.in_def and (len(self.identifiers.locally_assigned) > 0 or len(self.identifiers.argument_declared)>0): - self.printer.writeline("__M_locals = dict(%s)" % ','.join(["%s=%s" % (x, x) for x in self.identifiers.argument_declared])) + self.printer.writeline("__M_locals = __M_dict_builtin(%s)" % ','.join(["%s=%s" % (x, x) for x in self.identifiers.argument_declared])) self.write_variable_declares(self.identifiers, toplevel=True) @@ -497,7 +499,7 @@ class _GenerateRenderMethod(object): if not self.in_def and len(self.identifiers.locally_assigned) > 0: # if we are the "template" def, fudge locally declared/modified variables into the "__M_locals" dictionary, # which is used for def calls within the same template, to simulate "enclosing scope" - self.printer.writeline('__M_locals.update(dict([(__M_key, locals()[__M_key]) for __M_key in [%s] if __M_key in locals()]))' % ','.join([repr(x) for x in node.declared_identifiers()])) + self.printer.writeline('__M_locals.update(__M_dict_builtin([(__M_key, __M_locals_builtin()[__M_key]) for __M_key in [%s] if __M_key in __M_locals_builtin()]))' % ','.join([repr(x) for x in node.declared_identifiers()])) def visitIncludeTag(self, node): self.write_source_comment(node) diff --git a/test/template.py b/test/template.py index 634a9a3ea4a78929ad86cc9f55b32a5216caf71f..0c491f1a11c1c29cb6655fdc5f83a515d0367f62 100644 --- a/test/template.py +++ b/test/template.py @@ -218,11 +218,22 @@ class PageArgsTest(unittest.TestCase): def test_canuse_builtin_names(self): template = Template(""" - exception: ${exception} + exception: ${Exception} id: ${id} """) - assert flatten_result(template.render(id='some id', exception='some exception')) == "exception: some exception id: some id" - + assert flatten_result(template.render(id='some id', Exception='some exception')) == "exception: some exception id: some id" + + def test_dict_locals(self): + template = Template(""" + <% + dict = "this is dict" + locals = "this is locals" + %> + dict: ${dict} + locals: ${locals} + """) + assert flatten_result(template.render()) == "dict: this is dict locals: this is locals" + class IncludeTest(unittest.TestCase): def test_basic(self): lookup = TemplateLookup()