revamped jinja2 import system. the behavior is less confusing now, but it's not backwards compatible. I like it though ;)
--HG--
branch : trunk
diff --git a/jinja2/parser.py b/jinja2/parser.py
index 8db62de..daa7a0d 100644
--- a/jinja2/parser.py
+++ b/jinja2/parser.py
@@ -14,7 +14,7 @@
_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
- 'macro', 'include'])
+ 'macro', 'include', 'from', 'import'])
_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq', 'in'])
statement_end_tokens = set(['variable_end', 'block_end', 'in'])
_tuple_edge_tokens = set(['rparen']) | statement_end_tokens
@@ -145,22 +145,47 @@
def parse_include(self):
node = nodes.Include(lineno=self.stream.expect('include').lineno)
- expr = self.parse_expression()
- if self.stream.current.type is 'assign':
+ node.template = self.parse_expression()
+ return node
+
+ def parse_import(self):
+ node = nodes.Import(lineno=self.stream.expect('import').lineno)
+ node.template = self.parse_expression()
+ self.stream.expect('name:as')
+ node.target = self.stream.expect('name').value
+ if not nodes.Name(node.target, 'store').can_assign():
+ raise TemplateSyntaxError('can\'t assign imported template '
+ 'to %r' % node.target, node.lineno,
+ self.filename)
+ return node
+
+ def parse_from(self):
+ node = nodes.FromImport(lineno=self.stream.expect('from').lineno)
+ node.template = self.parse_expression()
+ self.stream.expect('import')
+ node.names = []
+ while 1:
+ if node.names:
+ self.stream.expect('comma')
+ if self.stream.current.type is 'name':
+ target = nodes.Name(self.stream.current.value, 'store')
+ if not target.can_assign():
+ raise TemplateSyntaxError('can\'t import object named %r'
+ % target.name, target.lineno,
+ self.filename)
+ elif target.name.startswith('__'):
+ raise TemplateAssertionError('names starting with two '
+ 'underscores can not be '
+ 'imported', target.lineno,
+ self.filename)
+ node.names.append(target.name)
+ self.stream.next()
+ if self.stream.current.type is not 'comma':
+ break
+ else:
+ break
+ if self.stream.current.type is 'comma':
self.stream.next()
- if not isinstance(expr, nodes.Name):
- raise TemplateSyntaxError('must assign imported template to '
- 'variable or current scope',
- expr.lineno, self.filename)
- if not expr.can_assign():
- raise TemplateSyntaxError('can\'t assign imported template '
- 'to %r' % expr, expr.lineno,
- self.filename)
- node.target = expr.name
- node.template = self.parse_expression()
- else:
- node.target = None
- node.template = expr
return node
def parse_signature(self, node):
@@ -568,8 +593,9 @@
self.stream.look().type is 'assign':
key = self.stream.current.value
self.stream.skip(2)
- kwargs.append(nodes.Keyword(key, self.parse_expression(),
- lineno=key.lineno))
+ value = self.parse_expression()
+ kwargs.append(nodes.Keyword(key, value,
+ lineno=value.lineno))
else:
ensure(not kwargs)
args.append(self.parse_expression())