# -*- coding: utf-8 -*- """ jinja._native ~~~~~~~~~~~~~ This module implements the native base classes in case of not having a jinja with the _speedups module compiled. Note that if you change semantics here you have to edit the _speedups.c file to in order to support those changes for jinja setups with enabled speedup module. :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ from jinja.datastructure import Deferred from jinja.utils import deque class BaseContext(object): def __init__(self, undefined_singleton, globals, initial): self._undefined_singleton = undefined_singleton self.current = current = {} self._stack = deque([current, initial, globals]) self.globals = globals self.initial = initial self._push = self._stack.appendleft self._pop = self._stack.popleft def stack(self): return list(self._stack)[::-1] stack = property(stack) def pop(self): """Pop the last layer from the stack and return it.""" rv = self._pop() self.current = self._stack[0] return rv def push(self, data=None): """ Push one layer to the stack and return it. Layer must be a dict or omitted. """ data = data or {} self._push(data) self.current = self._stack[0] return data def __getitem__(self, name): """ Resolve one item. Restrict the access to internal variables such as ``'::cycle1'``. Resolve deferreds. """ if not name.startswith('::'): for d in self._stack: if name in d: rv = d[name] if rv.__class__ is Deferred: rv = rv(self, name) # never touch the globals! if d is self.globals: self.initial[name] = rv else: d[name] = rv return rv return self._undefined_singleton def __setitem__(self, name, value): """Set a variable in the outermost layer.""" self.current[name] = value def __delitem__(self, name): """Delete a variable in the outermost layer.""" if name in self.current: del self.current[name] def __contains__(self, name): """ Check if the context contains a given variable.""" for layer in self._stack: if name in layer: return True return False