Skip to content

Commit

Permalink
removed unused imports
Browse files Browse the repository at this point in the history
--HG--
branch : trunk
  • Loading branch information
mitsuhiko committed May 13, 2008
1 parent 2e30cf5 commit 981cbf6
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 178 deletions.
11 changes: 0 additions & 11 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -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
---------------------

Expand Down
14 changes: 7 additions & 7 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down Expand Up @@ -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.
44 changes: 12 additions & 32 deletions jinja2/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,17 +310,13 @@ def lex(self, source, filename=None):
"""
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
Expand All @@ -330,7 +326,7 @@ def compile(self, source, name=None, filename=None, globals=None,
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
Expand Down Expand Up @@ -358,9 +354,8 @@ def get_template(self, name, parent=None, globals=None):
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.
Expand All @@ -387,8 +382,7 @@ def from_string(self, source, globals=None, template_class=None):
"""
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."""
Expand Down Expand Up @@ -513,24 +507,8 @@ def generate(self, *args, **kwargs):
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
Expand Down Expand Up @@ -668,8 +646,10 @@ def generator():
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
Expand Down
2 changes: 1 addition & 1 deletion jinja2/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def load(self, environment, name, globals=None):
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)

Expand Down
137 changes: 10 additions & 127 deletions jinja2/optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,156 +17,39 @@
: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):

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,
Expand Down

0 comments on commit 981cbf6

Please sign in to comment.