comparison genshi/template/base.py @ 703:af57b12e3dd2 experimental-match-fastpaths

merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
author aflett
date Mon, 31 Mar 2008 22:47:50 +0000
parents 3d7288f373bd
children 422d0607ba85
comparison
equal deleted inserted replaced
701:52a597419c0d 703:af57b12e3dd2
253 253
254 def pop(self): 254 def pop(self):
255 """Pop the top-most scope from the stack.""" 255 """Pop the top-most scope from the stack."""
256 256
257 257
258 def _apply_directives(stream, ctxt, directives): 258 def _apply_directives(stream, directives, ctxt, **vars):
259 """Apply the given directives to the stream. 259 """Apply the given directives to the stream.
260 260
261 :param stream: the stream the directives should be applied to 261 :param stream: the stream the directives should be applied to
262 :param directives: the list of directives to apply
262 :param ctxt: the `Context` 263 :param ctxt: the `Context`
263 :param directives: the list of directives to apply 264 :param vars: additional variables that should be available when Python
265 code is executed
264 :return: the stream with the given directives applied 266 :return: the stream with the given directives applied
265 """ 267 """
266 if directives: 268 if directives:
267 stream = directives[0](iter(stream), ctxt, directives[1:]) 269 stream = directives[0](iter(stream), directives[1:], ctxt, **vars)
268 return stream 270 return stream
271
272 def _eval_expr(expr, ctxt, **vars):
273 """Evaluate the given `Expression` object.
274
275 :param expr: the expression to evaluate
276 :param ctxt: the `Context`
277 :param vars: additional variables that should be available to the
278 expression
279 :return: the result of the evaluation
280 """
281 if vars:
282 ctxt.push(vars)
283 retval = expr.evaluate(ctxt)
284 if vars:
285 ctxt.pop()
286 return retval
287
288 def _exec_suite(suite, ctxt, **vars):
289 """Execute the given `Suite` object.
290
291 :param suite: the code suite to execute
292 :param ctxt: the `Context`
293 :param vars: additional variables that should be available to the
294 code
295 """
296 if vars:
297 ctxt.push(vars)
298 ctxt.push({})
299 suite.execute(_ctxt2dict(ctxt))
300 if vars:
301 top = ctxt.pop()
302 ctxt.pop()
303 ctxt.frames[0].update(top)
269 304
270 305
271 class TemplateMeta(type): 306 class TemplateMeta(type):
272 """Meta class for templates.""" 307 """Meta class for templates."""
273 308
425 This calling style is used for internal processing. 460 This calling style is used for internal processing.
426 461
427 :return: a markup event stream representing the result of applying 462 :return: a markup event stream representing the result of applying
428 the template to the context data. 463 the template to the context data.
429 """ 464 """
465 vars = {}
430 if args: 466 if args:
431 assert len(args) == 1 467 assert len(args) == 1
432 ctxt = args[0] 468 ctxt = args[0]
433 if ctxt is None: 469 if ctxt is None:
434 ctxt = Context(**kwargs) 470 ctxt = Context(**kwargs)
471 else:
472 vars = kwargs
435 assert isinstance(ctxt, Context) 473 assert isinstance(ctxt, Context)
436 else: 474 else:
437 ctxt = Context(**kwargs) 475 ctxt = Context(**kwargs)
438 476
439 stream = self.stream 477 stream = self.stream
440 for filter_ in self.filters: 478 for filter_ in self.filters:
441 stream = filter_(iter(stream), ctxt) 479 stream = filter_(iter(stream), ctxt, **vars)
442 return Stream(stream, self.serializer) 480 return Stream(stream, self.serializer)
443 481
444 def _eval(self, stream, ctxt): 482 def _eval(self, stream, ctxt, **vars):
445 """Internal stream filter that evaluates any expressions in `START` and 483 """Internal stream filter that evaluates any expressions in `START` and
446 `TEXT` events. 484 `TEXT` events.
447 """ 485 """
448 filters = (self._flatten, self._eval) 486 filters = (self._flatten, self._eval)
449 number_conv = self._number_conv 487 number_conv = self._number_conv
459 if isinstance(substream, basestring): 497 if isinstance(substream, basestring):
460 value = substream 498 value = substream
461 else: 499 else:
462 values = [] 500 values = []
463 for subkind, subdata, subpos in self._eval(substream, 501 for subkind, subdata, subpos in self._eval(substream,
464 ctxt): 502 ctxt,
503 **vars):
465 if subkind is TEXT: 504 if subkind is TEXT:
466 values.append(subdata) 505 values.append(subdata)
467 value = [x for x in values if x is not None] 506 value = [x for x in values if x is not None]
468 if not value: 507 if not value:
469 continue 508 continue
470 new_attrs.append((name, u''.join(value))) 509 new_attrs.append((name, u''.join(value)))
471 yield kind, (tag, Attrs(new_attrs)), pos 510 yield kind, (tag, Attrs(new_attrs)), pos
472 511
473 elif kind is EXPR: 512 elif kind is EXPR:
474 result = data.evaluate(ctxt) 513 result = _eval_expr(data, ctxt, **vars)
475 if result is not None: 514 if result is not None:
476 # First check for a string, otherwise the iterable test 515 # First check for a string, otherwise the iterable test
477 # below succeeds, and the string will be chopped up into 516 # below succeeds, and the string will be chopped up into
478 # individual characters 517 # individual characters
479 if isinstance(result, basestring): 518 if isinstance(result, basestring):
481 elif isinstance(result, (int, float, long)): 520 elif isinstance(result, (int, float, long)):
482 yield TEXT, number_conv(result), pos 521 yield TEXT, number_conv(result), pos
483 elif hasattr(result, '__iter__'): 522 elif hasattr(result, '__iter__'):
484 substream = _ensure(result) 523 substream = _ensure(result)
485 for filter_ in filters: 524 for filter_ in filters:
486 substream = filter_(substream, ctxt) 525 substream = filter_(substream, ctxt, **vars)
487 for event in substream: 526 for event in substream:
488 yield event 527 yield event
489 else: 528 else:
490 yield TEXT, unicode(result), pos 529 yield TEXT, unicode(result), pos
491 530
492 else: 531 else:
493 yield kind, data, pos 532 yield kind, data, pos
494 533
495 def _exec(self, stream, ctxt): 534 def _exec(self, stream, ctxt, **vars):
496 """Internal stream filter that executes Python code blocks.""" 535 """Internal stream filter that executes Python code blocks."""
497 for event in stream: 536 for event in stream:
498 if event[0] is EXEC: 537 if event[0] is EXEC:
499 event[1].execute(_ctxt2dict(ctxt)) 538 _exec_suite(event[1], ctxt, **vars)
500 else: 539 else:
501 yield event 540 yield event
502 541
503 def _flatten(self, stream, ctxt): 542 def _flatten(self, stream, ctxt, **vars):
504 """Internal stream filter that expands `SUB` events in the stream.""" 543 """Internal stream filter that expands `SUB` events in the stream."""
505 for event in stream: 544 for event in stream:
506 if event[0] is SUB: 545 if event[0] is SUB:
507 # This event is a list of directives and a list of nested 546 # This event is a list of directives and a list of nested
508 # events to which those directives should be applied 547 # events to which those directives should be applied
509 directives, substream = event[1] 548 directives, substream = event[1]
510 substream = _apply_directives(substream, ctxt, directives) 549 substream = _apply_directives(substream, directives, ctxt,
511 for event in self._flatten(substream, ctxt): 550 **vars)
551 for event in self._flatten(substream, ctxt, **vars):
512 yield event 552 yield event
513 else: 553 else:
514 yield event 554 yield event
515 555
516 def _include(self, stream, ctxt): 556 def _include(self, stream, ctxt, **vars):
517 """Internal stream filter that performs inclusion of external 557 """Internal stream filter that performs inclusion of external
518 template files. 558 template files.
519 """ 559 """
520 from genshi.template.loader import TemplateNotFound 560 from genshi.template.loader import TemplateNotFound
521 561
522 for event in stream: 562 for event in stream:
523 if event[0] is INCLUDE: 563 if event[0] is INCLUDE:
524 href, cls, fallback = event[1] 564 href, cls, fallback = event[1]
525 if not isinstance(href, basestring): 565 if not isinstance(href, basestring):
526 parts = [] 566 parts = []
527 for subkind, subdata, subpos in self._eval(href, ctxt): 567 for subkind, subdata, subpos in self._eval(href, ctxt,
568 **vars):
528 if subkind is TEXT: 569 if subkind is TEXT:
529 parts.append(subdata) 570 parts.append(subdata)
530 href = u''.join([x for x in parts if x is not None]) 571 href = u''.join([x for x in parts if x is not None])
531 try: 572 try:
532 tmpl = self.loader.load(href, relative_to=event[2][0], 573 tmpl = self.loader.load(href, relative_to=event[2][0],
533 cls=cls or self.__class__) 574 cls=cls or self.__class__)
534 for event in tmpl.generate(ctxt): 575 for event in tmpl.generate(ctxt, **vars):
535 yield event 576 yield event
536 except TemplateNotFound: 577 except TemplateNotFound:
537 if fallback is None: 578 if fallback is None:
538 raise 579 raise
539 for filter_ in self.filters: 580 for filter_ in self.filters:
540 fallback = filter_(iter(fallback), ctxt) 581 fallback = filter_(iter(fallback), ctxt, **vars)
541 for event in fallback: 582 for event in fallback:
542 yield event 583 yield event
543 else: 584 else:
544 yield event 585 yield event
545 586
Copyright (C) 2012-2017 Edgewall Software