Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/template/context.py: 26%
168 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from contextlib import contextmanager
2from copy import copy
4# Hard-coded processor for easier use of CSRF protection.
5_builtin_context_processors = ("django.template.context_processors.csrf",)
8class ContextPopException(Exception):
9 "pop() has been called more times than push()"
10 pass
13class ContextDict(dict):
14 def __init__(self, context, *args, **kwargs):
15 super().__init__(*args, **kwargs)
17 context.dicts.append(self)
18 self.context = context
20 def __enter__(self):
21 return self
23 def __exit__(self, *args, **kwargs):
24 self.context.pop()
27class BaseContext:
28 def __init__(self, dict_=None):
29 self._reset_dicts(dict_)
31 def _reset_dicts(self, value=None):
32 builtins = {"True": True, "False": False, "None": None}
33 self.dicts = [builtins]
34 if value is not None:
35 self.dicts.append(value)
37 def __copy__(self):
38 duplicate = copy(super())
39 duplicate.dicts = self.dicts[:]
40 return duplicate
42 def __repr__(self):
43 return repr(self.dicts)
45 def __iter__(self):
46 return reversed(self.dicts)
48 def push(self, *args, **kwargs):
49 dicts = []
50 for d in args:
51 if isinstance(d, BaseContext):
52 dicts += d.dicts[1:]
53 else:
54 dicts.append(d)
55 return ContextDict(self, *dicts, **kwargs)
57 def pop(self):
58 if len(self.dicts) == 1:
59 raise ContextPopException
60 return self.dicts.pop()
62 def __setitem__(self, key, value):
63 "Set a variable in the current context"
64 self.dicts[-1][key] = value
66 def set_upward(self, key, value):
67 """
68 Set a variable in one of the higher contexts if it exists there,
69 otherwise in the current context.
70 """
71 context = self.dicts[-1]
72 for d in reversed(self.dicts):
73 if key in d:
74 context = d
75 break
76 context[key] = value
78 def __getitem__(self, key):
79 "Get a variable's value, starting at the current context and going upward"
80 for d in reversed(self.dicts):
81 if key in d:
82 return d[key]
83 raise KeyError(key)
85 def __delitem__(self, key):
86 "Delete a variable from the current context"
87 del self.dicts[-1][key]
89 def __contains__(self, key):
90 return any(key in d for d in self.dicts)
92 def get(self, key, otherwise=None):
93 for d in reversed(self.dicts):
94 if key in d:
95 return d[key]
96 return otherwise
98 def setdefault(self, key, default=None):
99 try:
100 return self[key]
101 except KeyError:
102 self[key] = default
103 return default
105 def new(self, values=None):
106 """
107 Return a new context with the same properties, but with only the
108 values given in 'values' stored.
109 """
110 new_context = copy(self)
111 new_context._reset_dicts(values)
112 return new_context
114 def flatten(self):
115 """
116 Return self.dicts as one dictionary.
117 """
118 flat = {}
119 for d in self.dicts:
120 flat.update(d)
121 return flat
123 def __eq__(self, other):
124 """
125 Compare two contexts by comparing theirs 'dicts' attributes.
126 """
127 if not isinstance(other, BaseContext):
128 return NotImplemented
129 # flatten dictionaries because they can be put in a different order.
130 return self.flatten() == other.flatten()
133class Context(BaseContext):
134 "A stack container for variable context"
136 def __init__(self, dict_=None, autoescape=True, use_l10n=None, use_tz=None):
137 self.autoescape = autoescape
138 self.use_l10n = use_l10n
139 self.use_tz = use_tz
140 self.template_name = "unknown"
141 self.render_context = RenderContext()
142 # Set to the original template -- as opposed to extended or included
143 # templates -- during rendering, see bind_template.
144 self.template = None
145 super().__init__(dict_)
147 @contextmanager
148 def bind_template(self, template):
149 if self.template is not None:
150 raise RuntimeError("Context is already bound to a template")
151 self.template = template
152 try:
153 yield
154 finally:
155 self.template = None
157 def __copy__(self):
158 duplicate = super().__copy__()
159 duplicate.render_context = copy(self.render_context)
160 return duplicate
162 def update(self, other_dict):
163 "Push other_dict to the stack of dictionaries in the Context"
164 if not hasattr(other_dict, "__getitem__"):
165 raise TypeError("other_dict must be a mapping (dictionary-like) object.")
166 if isinstance(other_dict, BaseContext):
167 other_dict = other_dict.dicts[1:].pop()
168 return ContextDict(self, other_dict)
171class RenderContext(BaseContext):
172 """
173 A stack container for storing Template state.
175 RenderContext simplifies the implementation of template Nodes by providing a
176 safe place to store state between invocations of a node's `render` method.
178 The RenderContext also provides scoping rules that are more sensible for
179 'template local' variables. The render context stack is pushed before each
180 template is rendered, creating a fresh scope with nothing in it. Name
181 resolution fails if a variable is not found at the top of the RequestContext
182 stack. Thus, variables are local to a specific template and don't affect the
183 rendering of other templates as they would if they were stored in the normal
184 template context.
185 """
187 template = None
189 def __iter__(self):
190 yield from self.dicts[-1]
192 def __contains__(self, key):
193 return key in self.dicts[-1]
195 def get(self, key, otherwise=None):
196 return self.dicts[-1].get(key, otherwise)
198 def __getitem__(self, key):
199 return self.dicts[-1][key]
201 @contextmanager
202 def push_state(self, template, isolated_context=True):
203 initial = self.template
204 self.template = template
205 if isolated_context:
206 self.push()
207 try:
208 yield
209 finally:
210 self.template = initial
211 if isolated_context:
212 self.pop()
215class RequestContext(Context):
216 """
217 This subclass of template.Context automatically populates itself using
218 the processors defined in the engine's configuration.
219 Additional processors can be specified as a list of callables
220 using the "processors" keyword argument.
221 """
223 def __init__(
224 self,
225 request,
226 dict_=None,
227 processors=None,
228 use_l10n=None,
229 use_tz=None,
230 autoescape=True,
231 ):
232 super().__init__(dict_, use_l10n=use_l10n, use_tz=use_tz, autoescape=autoescape)
233 self.request = request
234 self._processors = () if processors is None else tuple(processors)
235 self._processors_index = len(self.dicts)
237 # placeholder for context processors output
238 self.update({})
240 # empty dict for any new modifications
241 # (so that context processors don't overwrite them)
242 self.update({})
244 @contextmanager
245 def bind_template(self, template):
246 if self.template is not None:
247 raise RuntimeError("Context is already bound to a template")
249 self.template = template
250 # Set context processors according to the template engine's settings.
251 processors = template.engine.template_context_processors + self._processors
252 updates = {}
253 for processor in processors:
254 updates.update(processor(self.request))
255 self.dicts[self._processors_index] = updates
257 try:
258 yield
259 finally:
260 self.template = None
261 # Unset context processors.
262 self.dicts[self._processors_index] = {}
264 def new(self, values=None):
265 new_context = super().new(values)
266 # This is for backwards-compatibility: RequestContexts created via
267 # Context.new don't include values from context processors.
268 if hasattr(new_context, "_processors_index"):
269 del new_context._processors_index
270 return new_context
273def make_context(context, request=None, **kwargs):
274 """
275 Create a suitable Context from a plain dict and optionally an HttpRequest.
276 """
277 if context is not None and not isinstance(context, dict):
278 raise TypeError(
279 "context must be a dict rather than %s." % context.__class__.__name__
280 )
281 if request is None:
282 context = Context(context, **kwargs)
283 else:
284 # The following pattern is required to ensure values from
285 # context override those from template context processors.
286 original_context = context
287 context = RequestContext(request, **kwargs)
288 if original_context:
289 context.push(original_context)
290 return context