summaryrefslogtreecommitdiff
path: root/django/template/__init__.py
diff options
context:
space:
mode:
authorBoulder Sprinters <boulder-sprinters@djangoproject.com>2007-06-18 16:43:17 +0000
committerBoulder Sprinters <boulder-sprinters@djangoproject.com>2007-06-18 16:43:17 +0000
commit750549569ea8d911db0397bd034406d5ce35d923 (patch)
treee516db51e7fb41b457c2caa64f54d7210128840f /django/template/__init__.py
parent1f09aa1e7b4079e22d1dfcde0f7d4e571389d8b5 (diff)
boulder-oracle-sprint: Merged to [5490]
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@5491 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/template/__init__.py')
-rw-r--r--django/template/__init__.py88
1 files changed, 57 insertions, 31 deletions
diff --git a/django/template/__init__.py b/django/template/__init__.py
index 4f2ddfc8b3..7495eea878 100644
--- a/django/template/__init__.py
+++ b/django/template/__init__.py
@@ -55,6 +55,7 @@ times with multiple contexts)
'\n<html>\n\n</html>\n'
"""
import re
+import types
from inspect import getargspec
from django.conf import settings
from django.template.context import Context, RequestContext, ContextPopException
@@ -167,9 +168,12 @@ class Template(object):
for subnode in node:
yield subnode
- def render(self, context):
+ def iter_render(self, context):
"Display stage -- can be called many times"
- return self.nodelist.render(context)
+ return self.nodelist.iter_render(context)
+
+ def render(self, context):
+ return ''.join(self.iter_render(context))
def compile_string(template_string, origin):
"Compiles template_string into NodeList ready for rendering"
@@ -488,9 +492,6 @@ class TokenParser(object):
self.pointer = i
return s
-
-
-
filter_raw_string = r"""
^%(i18n_open)s"(?P<i18n_constant>%(str)s)"%(i18n_close)s|
^"(?P<constant>%(str)s)"|
@@ -698,10 +699,26 @@ def resolve_variable(path, context):
del bits[0]
return current
+class NodeBase(type):
+ def __new__(cls, name, bases, attrs):
+ """
+ Ensures that either a 'render' or 'render_iter' method is defined on
+ any Node sub-class. This avoids potential infinite loops at runtime.
+ """
+ if not (isinstance(attrs.get('render'), types.FunctionType) or
+ isinstance(attrs.get('iter_render'), types.FunctionType)):
+ raise TypeError('Unable to create Node subclass without either "render" or "iter_render" method.')
+ return type.__new__(cls, name, bases, attrs)
+
class Node(object):
+ __metaclass__ = NodeBase
+
+ def iter_render(self, context):
+ return (self.render(context),)
+
def render(self, context):
"Return the node rendered as a string"
- pass
+ return ''.join(self.iter_render(context))
def __iter__(self):
yield self
@@ -717,13 +734,12 @@ class Node(object):
class NodeList(list):
def render(self, context):
- bits = []
+ return ''.join(self.iter_render(context))
+
+ def iter_render(self, context):
for node in self:
- if isinstance(node, Node):
- bits.append(self.render_node(node, context))
- else:
- bits.append(node)
- return ''.join(bits)
+ for chunk in node.iter_render(context):
+ yield chunk
def get_nodes_by_type(self, nodetype):
"Return a list of all nodes of the given type"
@@ -732,24 +748,25 @@ class NodeList(list):
nodes.extend(node.get_nodes_by_type(nodetype))
return nodes
- def render_node(self, node, context):
- return(node.render(context))
-
class DebugNodeList(NodeList):
- def render_node(self, node, context):
- try:
- result = node.render(context)
- except TemplateSyntaxError, e:
- if not hasattr(e, 'source'):
- e.source = node.source
- raise
- except Exception, e:
- from sys import exc_info
- wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e)
- wrapped.source = node.source
- wrapped.exc_info = exc_info()
- raise wrapped
- return result
+ def iter_render(self, context):
+ for node in self:
+ if not isinstance(node, Node):
+ yield node
+ continue
+ try:
+ for chunk in node.iter_render(context):
+ yield chunk
+ except TemplateSyntaxError, e:
+ if not hasattr(e, 'source'):
+ e.source = node.source
+ raise
+ except Exception, e:
+ from sys import exc_info
+ wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e)
+ wrapped.source = node.source
+ wrapped.exc_info = exc_info()
+ raise wrapped
class TextNode(Node):
def __init__(self, s):
@@ -758,6 +775,9 @@ class TextNode(Node):
def __repr__(self):
return "<Text Node: '%s'>" % self.s[:25]
+ def iter_render(self, context):
+ return (self.s,)
+
def render(self, context):
return self.s
@@ -781,6 +801,9 @@ class VariableNode(Node):
else:
return output
+ def iter_render(self, context):
+ return (self.render(context),)
+
def render(self, context):
output = self.filter_expression.resolve(context)
return self.encode_output(output)
@@ -869,6 +892,9 @@ class Library(object):
def __init__(self, vars_to_resolve):
self.vars_to_resolve = vars_to_resolve
+ #def iter_render(self, context):
+ # return (self.render(context),)
+
def render(self, context):
resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
return func(*resolved_vars)
@@ -891,7 +917,7 @@ class Library(object):
def __init__(self, vars_to_resolve):
self.vars_to_resolve = vars_to_resolve
- def render(self, context):
+ def iter_render(self, context):
resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
if takes_context:
args = [context] + resolved_vars
@@ -907,7 +933,7 @@ class Library(object):
else:
t = get_template(file_name)
self.nodelist = t.nodelist
- return self.nodelist.render(context_class(dict))
+ return self.nodelist.iter_render(context_class(dict))
compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, InclusionNode)
compile_func.__doc__ = func.__doc__