- can now use most names from __builtins__ as variable
names without explicit declaration (i.e. 'id',
'exception', 'range', etc.) [ticket:83]
diff --git a/CHANGES b/CHANGES
index 7e5c11c..7036ee9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -48,7 +48,10 @@
caller_stack._push_frame(), caller_stack._pop_frame().
- Bugfixes:
-
+ - can now use most names from __builtins__ as variable
+ names without explicit declaration (i.e. 'id',
+ 'exception', 'range', etc.) [ticket:83]
+
- fixed bug in python generation when variable names are
used with identifiers like "else", "finally", etc.
inside them [ticket:68]
diff --git a/lib/mako/pyparser.py b/lib/mako/pyparser.py
index 372222f..df21a9b 100644
--- a/lib/mako/pyparser.py
+++ b/lib/mako/pyparser.py
@@ -9,11 +9,14 @@
Parsing to AST is done via _ast on Python > 2.5, otherwise the compiler
module is used.
"""
-import __builtin__
+
import sys
from StringIO import StringIO
from mako import exceptions, util
+# words that cannot be assigned to (notably smaller than the total keys in __builtins__)
+reserved = set(['True', 'False', 'None'])
+
new_ast = sys.version_info > (2, 5)
if new_ast:
@@ -89,7 +92,7 @@
def visit_Name(self, node):
if isinstance(node.ctx, _ast.Store):
self._add_declared(node.id)
- if not hasattr(__builtin__, node.id) and node.id not in self.listener.declared_identifiers and node.id not in self.local_ident_stack:
+ if node.id not in reserved and node.id not in self.listener.declared_identifiers and node.id not in self.local_ident_stack:
self.listener.undeclared_identifiers.add(node.id)
def visit_Import(self, node):
for name in node.names:
@@ -187,7 +190,7 @@
self.visit(node.assign, *args)
self.visit(node.body, *args)
def visitName(self, node, *args):
- if not hasattr(__builtin__, node.name) and node.name not in self.listener.declared_identifiers and node.name not in self.local_ident_stack:
+ if node.name not in reserved and node.name not in self.listener.declared_identifiers and node.name not in self.local_ident_stack:
self.listener.undeclared_identifiers.add(node.name)
def visitImport(self, node, *args):
for (mod, alias) in node.names:
diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py
index 7704a95..b181287 100644
--- a/lib/mako/runtime.py
+++ b/lib/mako/runtime.py
@@ -8,21 +8,23 @@
from mako import exceptions, util
import inspect, sys
+import __builtin__
class Context(object):
"""provides runtime namespace, output buffer, and various callstacks for templates."""
def __init__(self, buffer, **data):
self._buffer_stack = [buffer]
- self._data = data
+ self._data = dict(__builtin__.__dict__)
+ self._data.update(data)
self._kwargs = data.copy()
self._with_template = None
self.namespaces = {}
# "capture" function which proxies to the generic "capture" function
- data['capture'] = lambda x, *args, **kwargs: capture(self, x, *args, **kwargs)
+ self._data['capture'] = lambda x, *args, **kwargs: capture(self, x, *args, **kwargs)
# "caller" stack used by def calls with content
- self.caller_stack = data['caller'] = CallerStack()
+ self.caller_stack = self._data['caller'] = CallerStack()
lookup = property(lambda self:self._with_template.lookup)
kwargs = property(lambda self:self._kwargs.copy())
diff --git a/test/ast.py b/test/ast.py
index 8f348e5..f60be65 100644
--- a/test/ast.py
+++ b/test/ast.py
@@ -56,7 +56,7 @@
(q for q in range (1, q))
"""
parsed = ast.PythonCode(code, **exception_kwargs)
- assert parsed.undeclared_identifiers == util.Set(['x', 'y', 'z', 'q'])
+ assert parsed.undeclared_identifiers == util.Set(['x', 'y', 'z', 'q', 'range'])
def test_locate_identifiers_4(self):
code = """
diff --git a/test/template.py b/test/template.py
index 123bfdf..634a9a3 100644
--- a/test/template.py
+++ b/test/template.py
@@ -215,6 +215,13 @@
""")
assert flatten_result(template.render(id="im the id")) == "this is page, id is im the id"
+
+ def test_canuse_builtin_names(self):
+ template = Template("""
+ exception: ${exception}
+ id: ${id}
+ """)
+ assert flatten_result(template.render(id='some id', exception='some exception')) == "exception: some exception id: some id"
class IncludeTest(unittest.TestCase):
def test_basic(self):