Ticket #230: genshi-context.patch
| File genshi-context.patch, 7.1 KB (added by dan.colascione@…, 15 years ago) |
|---|
-
genshi/template/base.py
30 30 'TemplateSyntaxError', 'BadDirectiveError'] 31 31 __docformat__ = 'restructuredtext en' 32 32 33 if sys.version_info < (2, 4):34 _ctxt2dict = lambda ctxt: ctxt.frames[0]35 else:36 _ctxt2dict = lambda ctxt: ctxt37 38 39 33 class TemplateError(Exception): 40 34 """Base exception class for errors related to template processing.""" 41 35 … … 133 127 """Initialize the template context with the given keyword arguments as 134 128 data. 135 129 """ 136 self.frames = deque([data]) 137 self.pop = self.frames.popleft 138 self.push = self.frames.appendleft 130 self.__frames = deque([data]) 139 131 self._match_templates = [] 140 132 self._choice_stack = [] 141 133 … … 152 144 data.setdefault('value_of', value_of) 153 145 154 146 def __repr__(self): 155 return repr(list(self. frames))147 return repr(list(self.__frames)) 156 148 157 149 def __contains__(self, key): 158 150 """Return whether a variable exists in any of the scopes. 159 151 160 152 :param key: the name of the variable 161 153 """ 162 return self._ find(key)[1] is not None154 return self.__find(key)[1] is not None 163 155 has_key = __contains__ 164 156 165 def __delitem__(self, key):166 """Remove a variable from all scopes.167 168 :param key: the name of the variable169 """170 for frame in self.frames:171 if key in frame:172 del frame[key]173 174 157 def __getitem__(self, key): 175 158 """Get a variables's value, starting at the current scope and going 176 159 upward. … … 179 162 :return: the variable value 180 163 :raises KeyError: if the requested variable wasn't found in any scope 181 164 """ 182 value, frame = self._ find(key)165 value, frame = self.__find(key) 183 166 if frame is None: 184 167 raise KeyError(key) 185 168 return value … … 197 180 :param key: the name of the variable 198 181 :param value: the variable value 199 182 """ 200 self. frames[0][key] = value183 self.__frames[0][key] = value 201 184 202 def _ find(self, key, default=None):185 def __find(self, key, default=None): 203 186 """Retrieve a given variable's value and the frame it was found in. 204 187 205 Inte nded primarily for internal use by directives.188 Internal use. 206 189 207 190 :param key: the name of the variable 208 191 :param default: the default value to return when the variable is not 209 192 found 210 193 """ 211 for frame in self. frames:194 for frame in self.__frames: 212 195 if key in frame: 213 196 return frame[key], frame 214 197 return default, None … … 221 204 :param default: the default value to return when the variable is not 222 205 found 223 206 """ 224 for frame in self. frames:207 for frame in self.__frames: 225 208 if key in frame: 226 209 return frame[key] 227 210 return default … … 232 215 :return: a list of variable names 233 216 """ 234 217 keys = [] 235 for frame in self. frames:218 for frame in self.__frames: 236 219 keys += [key for key in frame if key not in keys] 237 220 return keys 238 221 … … 246 229 247 230 def update(self, mapping): 248 231 """Update the context from the mapping provided.""" 249 self. frames[0].update(mapping)232 self.__frames[0].update(mapping) 250 233 251 234 def push(self, data): 252 235 """Push a new scope on the stack. … … 254 237 :param data: the data dictionary to push on the context stack. 255 238 """ 256 239 240 self.__frames.appendleft(data) 241 257 242 def pop(self): 258 243 """Pop the top-most scope from the stack.""" 259 244 245 return self.__frames.popleft() 260 246 247 def execdict(self): 248 """Return an object Python's exec can use for variables""" 249 250 if sys.version_info < (2, 4): 251 return self.__frames[0] 252 else: 253 return self 254 261 255 def _apply_directives(stream, directives, ctxt, **vars): 262 256 """Apply the given directives to the stream. 263 257 … … 299 293 if vars: 300 294 ctxt.push(vars) 301 295 ctxt.push({}) 302 suite.execute( _ctxt2dict(ctxt))296 suite.execute(ctxt.execdict()) 303 297 if vars: 304 298 top = ctxt.pop() 305 299 ctxt.pop() 306 ctxt. frames[0].update(top)300 ctxt.update(top) 307 301 308 302 309 303 class TemplateMeta(type): -
genshi/template/tests/markup.py
254 254 <Item/> 255 255 </Test>""", str(tmpl.generate())) 256 256 257 def test_included_function_override(self): 258 dirname = tempfile.mkdtemp(suffix='genshi_test') 259 try: 260 file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w') 261 try: 262 file1.write("""<div xmlns:xi="http://www.w3.org/2001/XInclude" 263 xmlns:py="http://genshi.edgewall.org/"> 264 <py:def function="msg">Foo</py:def> 265 <xi:include href="tmpl2.html" />${msg()}</div>""") 266 finally: 267 file1.close() 268 269 file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w') 270 try: 271 file2.write("""<py:def 272 xmlns:py="http://genshi.edgewall.org/" 273 function="msg">Bar</py:def>""") 274 finally: 275 file2.close() 276 277 loader = TemplateLoader([dirname]) 278 tmpl = loader.load('tmpl1.html') 279 280 self.assertEqual("""<div> 281 Bar</div>""", tmpl.generate().render()) 282 283 finally: 284 shutil.rmtree(dirname) 285 257 286 def test_include_in_loop(self): 258 287 dirname = tempfile.mkdtemp(suffix='genshi_test') 259 288 try: -
genshi/template/directives.py
322 322 # Function name can't be set in Python 2.3 323 323 pass 324 324 325 # Store the function reference in the bottom context frame so that it 326 # doesn't get popped off before processing the template has finished 327 # FIXME: this makes context data mutable as a side-effect 328 ctxt.frames[-1][self.name] = function 325 ctxt[self.name] = function 329 326 330 327 return [] 331 328 … … 731 728 attach = classmethod(attach) 732 729 733 730 def __call__(self, stream, directives, ctxt, **vars): 734 frame = {}735 ctxt.push(frame)731 ctxt.push({}) 732 736 733 for targets, expr in self.vars: 737 734 value = _eval_expr(expr, ctxt, **vars) 738 735 for assign in targets: 739 assign(frame, value) 736 assign(ctxt, value) 737 740 738 for event in _apply_directives(stream, directives, ctxt, **vars): 741 739 yield event 742 740 ctxt.pop()
