diff options
| author | Boulder Sprinters <boulder-sprinters@djangoproject.com> | 2007-06-18 16:43:17 +0000 |
|---|---|---|
| committer | Boulder Sprinters <boulder-sprinters@djangoproject.com> | 2007-06-18 16:43:17 +0000 |
| commit | 750549569ea8d911db0397bd034406d5ce35d923 (patch) | |
| tree | e516db51e7fb41b457c2caa64f54d7210128840f /django/template/__init__.py | |
| parent | 1f09aa1e7b4079e22d1dfcde0f7d4e571389d8b5 (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__.py | 88 |
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__ |
