diff -r 8d941af65caf -r 77b6da96e6f1 web/lib/django/template/context.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/django/template/context.py Wed Jun 02 18:57:35 2010 +0200 @@ -0,0 +1,149 @@ +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 BaseContext(object): + def __init__(self, dict_=None): + dict_ = dict_ or {} + self.dicts = [dict_] + + def __repr__(self): + return repr(self.dicts) + + def __iter__(self): + for d in reversed(self.dicts): + yield d + + def push(self): + d = {} + self.dicts.append(d) + return d + + def pop(self): + if len(self.dicts) == 1: + raise ContextPopException + return self.dicts.pop() + + def __setitem__(self, key, value): + "Set a variable in the current context" + 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 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[-1][key] + + def has_key(self, key): + for d in self.dicts: + if key in d: + return True + return False + + def __contains__(self, key): + return self.has_key(key) + + def get(self, key, otherwise=None): + 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.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(): + from django.conf import settings + global _standard_context_processors + if _standard_context_processors is None: + 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: + mod = import_module(module) + except ImportError, e: + raise ImproperlyConfigured('Error importing request processor module %s: "%s"' % (module, e)) + try: + func = getattr(mod, attr) + except AttributeError: + raise ImproperlyConfigured('Module "%s" does not define a "%s" callable request processor' % (module, attr)) + processors.append(func) + _standard_context_processors = tuple(processors) + return _standard_context_processors + +class RequestContext(Context): + """ + This subclass of template.Context automatically populates itself using + the processors defined in TEMPLATE_CONTEXT_PROCESSORS. + Additional processors can be specified as a list of callables + using the "processors" keyword argument. + """ + def __init__(self, request, dict=None, processors=None, current_app=None): + Context.__init__(self, dict, current_app=current_app) + if processors is None: + processors = () + else: + processors = tuple(processors) + for processor in get_standard_processors() + processors: + self.update(processor(request))