diff -r b758351d191f -r cc9b7e14412b web/lib/django/template/context.py --- a/web/lib/django/template/context.py Wed May 19 17:43:59 2010 +0200 +++ b/web/lib/django/template/context.py Tue May 25 02:43:45 2010 +0200 @@ -1,51 +1,53 @@ from django.core.exceptions import ImproperlyConfigured from django.utils.importlib import import_module +# Cache of actual callables. _standard_context_processors = None +# We need the CSRF processor no matter what the user has in their settings, +# because otherwise it is a security vulnerability, and we can't afford to leave +# this to human error or failure to read migration instructions. +_builtin_context_processors = ('django.core.context_processors.csrf',) class ContextPopException(Exception): "pop() has been called more times than push()" pass -class Context(object): - "A stack container for variable context" - def __init__(self, dict_=None, autoescape=True, current_app=None): +class BaseContext(object): + def __init__(self, dict_=None): dict_ = dict_ or {} self.dicts = [dict_] - self.autoescape = autoescape - self.current_app = current_app def __repr__(self): return repr(self.dicts) def __iter__(self): - for d in self.dicts: + for d in reversed(self.dicts): yield d def push(self): d = {} - self.dicts = [d] + self.dicts + self.dicts.append(d) return d def pop(self): if len(self.dicts) == 1: raise ContextPopException - return self.dicts.pop(0) + return self.dicts.pop() def __setitem__(self, key, value): "Set a variable in the current context" - self.dicts[0][key] = value + self.dicts[-1][key] = value def __getitem__(self, key): "Get a variable's value, starting at the current context and going upward" - for d in self.dicts: + for d in reversed(self.dicts): if key in d: return d[key] raise KeyError(key) def __delitem__(self, key): "Delete a variable from the current context" - del self.dicts[0][key] + del self.dicts[-1][key] def has_key(self, key): for d in self.dicts: @@ -53,21 +55,58 @@ return True return False - __contains__ = has_key + def __contains__(self, key): + return self.has_key(key) def get(self, key, otherwise=None): - for d in self.dicts: + for d in reversed(self.dicts): if key in d: return d[key] return otherwise +class Context(BaseContext): + "A stack container for variable context" + def __init__(self, dict_=None, autoescape=True, current_app=None): + self.autoescape = autoescape + self.current_app = current_app + self.render_context = RenderContext() + super(Context, self).__init__(dict_) + def update(self, other_dict): "Like dict.update(). Pushes an entire dictionary's keys and values onto the context." if not hasattr(other_dict, '__getitem__'): raise TypeError('other_dict must be a mapping (dictionary-like) object.') - self.dicts = [other_dict] + self.dicts + self.dicts.append(other_dict) return other_dict +class RenderContext(BaseContext): + """ + A stack container for storing Template state. + + RenderContext simplifies the implementation of template Nodes by providing a + safe place to store state between invocations of a node's `render` method. + + The RenderContext also provides scoping rules that are more sensible for + 'template local' variables. The render context stack is pushed before each + template is rendered, creating a fresh scope with nothing in it. Name + resolution fails if a variable is not found at the top of the RequestContext + stack. Thus, variables are local to a specific template and don't affect the + rendering of other templates as they would if they were stored in the normal + template context. + """ + def __iter__(self): + for d in self.dicts[-1]: + yield d + + def has_key(self, key): + return key in self.dicts[-1] + + def get(self, key, otherwise=None): + d = self.dicts[-1] + if key in d: + return d[key] + return otherwise + # This is a function rather than module-level procedural code because we only # want it to execute if somebody uses RequestContext. def get_standard_processors(): @@ -75,7 +114,10 @@ global _standard_context_processors if _standard_context_processors is None: processors = [] - for path in settings.TEMPLATE_CONTEXT_PROCESSORS: + collect = [] + collect.extend(_builtin_context_processors) + collect.extend(settings.TEMPLATE_CONTEXT_PROCESSORS) + for path in collect: i = path.rfind('.') module, attr = path[:i], path[i+1:] try: