removed unused imports
authorArmin Ronacher <armin.ronacher@active-4.com>
Tue, 13 May 2008 07:12:27 +0000 (09:12 +0200)
committerArmin Ronacher <armin.ronacher@active-4.com>
Tue, 13 May 2008 07:12:27 +0000 (09:12 +0200)
--HG--
branch : trunk

TODO
docs/api.rst
jinja2/environment.py
jinja2/loaders.py
jinja2/optimizer.py

diff --git a/TODO b/TODO
index 2a022f424f3096bcae4b51f4a54a73697ad5ccca..a95193680f0f5a59a3d03e0e13328801b960a982 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,17 +3,6 @@ Todo Before Release
 
 This has to be implemented before the release:
 
-Drop special casing template globals
-------------------------------------
-
-The idea some time ago was to partially evaluate templates at compile time.
-For that we decided to not allow globals being overridden by locals as the
-static compiler could have changed semantics.  Turns out that the static
-compiler blows up the complexity to something nobody wants to support which
-means that this restriction is kinda pointless.
-
-That should go for good.
-
 Pull Attributes Onces
 ---------------------
 
index 8d852429ed73a174d88077e7a643ee137014d181..5b9e5aded74a3b07df797a304ffd0844d9580a7b 100644 (file)
@@ -81,8 +81,7 @@ High Level API
     .. attribute:: globals
 
         A dict of global variables.  These variables are always available
-        in a template and (if the optimizer is enabled) may not be
-        overridden by templates.  As long as no template was loaded it's safe
+        in a template.  As long as no template was loaded it's safe
         to modify this dict.  For more details see :ref:`global-namespace`.
         For valid object names have a look at :ref:`identifier-naming`.
 
@@ -364,8 +363,9 @@ A template designer can then use the test like this:
 The Global Namespace
 --------------------
 
-Variables stored in the :attr:`Environment.globals` or :attr:`Template.globals`
-dicts are special as they are available for imported templates too and will be
-used by the optimizer in future releases to evaluates parts of the template at
-compile time.  This is the place where you can put variables and functions
-that should be available all the time.
+Variables stored in the :attr:`Environment.globals` dict are special as they
+are available for imported templates too, even if they are imported without
+context.  This is the place where you can put variables and functions
+that should be available all the time.  Additionally :attr:`Template.globals`
+exist that are variables available to a specific template that are available
+to all :meth:`~Template.render` calls.
index e1040900aacb15c9761f8f95ed0b198acd7e4a5a..70fd3446c19060867aac6d02550a3ea87a4599db 100644 (file)
@@ -310,17 +310,13 @@ class Environment(object):
         """
         return self.lexer.tokeniter(source, filename)
 
-    def compile(self, source, name=None, filename=None, globals=None,
-                raw=False):
+    def compile(self, source, name=None, filename=None, raw=False):
         """Compile a node or template source code.  The `name` parameter is
         the load name of the template after it was joined using
         :meth:`join_path` if necessary, not the filename on the file system.
         the `filename` parameter is the estimated filename of the template on
         the file system.  If the template came from a database or memory this
-        can be omitted.  The `globals` parameter can be used to provide extra
-        variables at compile time for the template.  In the future the
-        optimizer will be able to evaluate parts of the template at compile
-        time based on those variables.
+        can be omitted.
 
         The return value of this method is a python code object.  If the `raw`
         parameter is `True` the return value will be a string with python
@@ -330,7 +326,7 @@ class Environment(object):
         if isinstance(source, basestring):
             source = self.parse(source, filename)
         if self.optimized:
-            node = optimize(source, self, globals or {})
+            node = optimize(source, self)
         source = generate(node, self, name, filename)
         if raw:
             return source
@@ -358,9 +354,8 @@ class Environment(object):
         If the `parent` parameter is not `None`, :meth:`join_path` is called
         to get the real template name before loading.
 
-        The `globals` parameter can be used to provide compile-time globals.
-        In the future this will allow the optimizer to render parts of the
-        templates at compile-time.
+        The `globals` parameter can be used to provide temlate wide globals.
+        These variables are available in the context at render time.
 
         If the template does not exist a :exc:`TemplateNotFound` exception is
         raised.
@@ -387,8 +382,7 @@ class Environment(object):
         """
         globals = self.make_globals(globals)
         cls = template_class or self.template_class
-        return cls.from_code(self, self.compile(source, globals=globals),
-                             globals, None)
+        return cls.from_code(self, self.compile(source), globals, None)
 
     def make_globals(self, d):
         """Return a dict for the globals."""
@@ -513,24 +507,8 @@ class Template(object):
             raise exc_type, exc_value, tb
 
     def _generate(self, *args, **kwargs):
-        # assemble the context
-        context = dict(*args, **kwargs)
-
-        # if the environment is using the optimizer locals may never
-        # override globals as optimizations might have happened
-        # depending on values of certain globals.  This assertion goes
-        # away if the python interpreter is started with -O
-        if __debug__ and self.environment.optimized:
-            overrides = set(context) & set(self.globals)
-            if overrides:
-                plural = len(overrides) != 1 and 's' or ''
-                raise AssertionError('the per template variable%s %s '
-                                     'override%s global variable%s. '
-                                     'With an enabled optimizer this '
-                                     'will lead to unexpected results.' %
-                    (plural, ', '.join(overrides), plural or ' a', plural))
-
-        return self.root_render_func(self.new_context(context))
+        """Creates a new context and generates the template."""
+        return self.root_render_func(self.new_context(dict(*args, **kwargs)))
 
     def new_context(self, vars=None, shared=False):
         """Create a new template context for this template.  The vars
@@ -668,8 +646,10 @@ class TemplateStream(object):
             while 1:
                 try:
                     while c_size < size:
-                        push(next())
-                        c_size += 1
+                        c = next()
+                        push(c)
+                        if c:
+                            c_size += 1
                 except StopIteration:
                     if not c_size:
                         return
index a63cdbfe5c53ff0fb2a88e99cfbed8dfaf498045..eb27f1749516b56ecc910f8612ff850c96ce57df 100644 (file)
@@ -86,7 +86,7 @@ class BaseLoader(object):
         if globals is None:
             globals = {}
         source, filename, uptodate = self.get_source(environment, name)
-        code = environment.compile(source, name, filename, globals)
+        code = environment.compile(source, name, filename)
         return environment.template_class.from_code(environment, code,
                                                     globals, uptodate)
 
index 283d1fae5637493aec61f722a995bec87b4edfd9..5b95c99a4027db427ec40df499a0ac0395c73993 100644 (file)
     :license: GNU GPL.
 """
 from jinja2 import nodes
-from jinja2.visitor import NodeVisitor, NodeTransformer
-from jinja2.runtime import LoopContext
-from jinja2.utils import concat
+from jinja2.visitor import NodeTransformer
 
 
-def optimize(node, environment, context_hint=None):
+def optimize(node, environment):
     """The context hint can be used to perform an static optimization
     based on the context given."""
     optimizer = Optimizer(environment)
-    return optimizer.visit(node, ContextStack(context_hint))
-
-
-class ContextStack(object):
-    """Simple compile time context implementation."""
-    undefined = object()
-
-    def __init__(self, initial=None):
-        self.stack = [{}]
-        if initial is not None:
-            self.stack.insert(0, initial)
-
-    def push(self):
-        self.stack.append({})
-
-    def pop(self):
-        self.stack.pop()
-
-    def get(self, key, default=None):
-        try:
-            return self[key]
-        except KeyError:
-            return default
-
-    def undef(self, name):
-        if name in self:
-            self[name] = self.undefined
-
-    def __contains__(self, key):
-        try:
-            self[key]
-        except KeyError:
-            return False
-        return True
-
-    def __getitem__(self, key):
-        for level in reversed(self.stack):
-            if key in level:
-                rv = level[key]
-                if rv is self.undefined:
-                    raise KeyError(key)
-                return rv
-        raise KeyError(key)
-
-    def __setitem__(self, key, value):
-        self.stack[-1][key] = value
-
-    def blank(self):
-        """Return a new context with nothing but the root scope."""
-        return ContextStack(self.stack[0])
+    return optimizer.visit(node)
 
 
 class Optimizer(NodeTransformer):
@@ -83,90 +32,24 @@ class Optimizer(NodeTransformer):
     def __init__(self, environment):
         self.environment = environment
 
-    def visit_Block(self, node, context):
-        block_context = context.blank()
-        for name in 'super', 'self':
-            block_context.undef(name)
-        return self.generic_visit(node, block_context)
-
-    def visit_For(self, node, context):
-        context.push()
-        context.undef('loop')
-        try:
-            return self.generic_visit(node, context)
-        finally:
-            context.pop()
-
-    def visit_Macro(self, node, context):
-        context.push()
-        for name in 'varargs', 'kwargs', 'caller':
-            context.undef(name)
-        try:
-            return self.generic_visit(node, context)
-        finally:
-            context.pop()
-
-    def visit_CallBlock(self, node, context):
-        context.push()
-        for name in 'varargs', 'kwargs':
-            context.undef(name)
-        try:
-            return self.generic_visit(node, context)
-        finally:
-            context.pop()
-
-    def visit_FilterBlock(self, node, context):
-        """Try to filter a block at compile time."""
-        context.push()
-        try:
-            return self.generic_visit(node, context)
-        finally:
-            context.pop()
-
-    def visit_If(self, node, context):
+    def visit_If(self, node):
+        """Eliminate dead code."""
         try:
-            val = self.visit(node.test, context).as_const()
+            val = self.visit(node.test).as_const()
         except nodes.Impossible:
-            return self.generic_visit(node, context)
+            return self.generic_visit(node)
         if val:
             body = node.body
         else:
             body = node.else_
         result = []
         for node in body:
-            result.extend(self.visit_list(node, context))
+            result.extend(self.visit_list(node))
         return result
 
-    def visit_Name(self, node, context):
-        if node.ctx != 'load':
-            # something overwrote the variable, we can no longer use
-            # the constant from the context
-            context.undef(node.name)
-            return node
-        try:
-            return nodes.Const.from_untrusted(context[node.name],
-                                              lineno=node.lineno,
-                                              environment=self.environment)
-        except (KeyError, nodes.Impossible):
-            return node
-
-    def visit_Import(self, node, context):
-        rv = self.generic_visit(node, context)
-        context.undef(node.target)
-        return rv
-
-    def visit_FromImport(self, node, context):
-        rv = self.generic_visit(node, context)
-        for name in node.names:
-            if isinstance(name, tuple):
-                context.undef(name[1])
-            else:
-                context.undef(name)
-        return rv
-
-    def fold(self, node, context):
+    def fold(self, node):
         """Do constant folding."""
-        node = self.generic_visit(node, context)
+        node = self.generic_visit(node)
         try:
             return nodes.Const.from_untrusted(node.as_const(),
                                               lineno=node.lineno,