Mercurial > genshi > mirror
comparison genshi/template/base.py @ 1033:348ba73df25c stable-0.6.x
Merge r1257 from trunk (fix for infinite template inlining).
author | hodgestar |
---|---|
date | Wed, 19 Mar 2014 13:56:46 +0000 |
parents | cccbcbd33e90 |
children |
comparison
equal
deleted
inserted
replaced
1018:fa0e84724fee | 1033:348ba73df25c |
---|---|
449 self.loader = TemplateLoader([os.path.abspath(basedir)]) | 449 self.loader = TemplateLoader([os.path.abspath(basedir)]) |
450 | 450 |
451 @property | 451 @property |
452 def stream(self): | 452 def stream(self): |
453 if not self._prepared: | 453 if not self._prepared: |
454 self._stream = list(self._prepare(self._stream)) | 454 self._prepare_self() |
455 self._prepared = True | |
456 return self._stream | 455 return self._stream |
457 | 456 |
458 def _parse(self, source, encoding): | 457 def _parse(self, source, encoding): |
459 """Parse the template. | 458 """Parse the template. |
460 | 459 |
467 template, or an XML event stream | 466 template, or an XML event stream |
468 :param encoding: the encoding of the `source` | 467 :param encoding: the encoding of the `source` |
469 """ | 468 """ |
470 raise NotImplementedError | 469 raise NotImplementedError |
471 | 470 |
472 def _prepare(self, stream): | 471 def _prepare_self(self, inlined=None): |
472 if not self._prepared: | |
473 self._stream = list(self._prepare(self._stream, inlined)) | |
474 self._prepared = True | |
475 | |
476 def _prepare(self, stream, inlined): | |
473 """Call the `attach` method of every directive found in the template. | 477 """Call the `attach` method of every directive found in the template. |
474 | 478 |
475 :param stream: the event stream of the template | 479 :param stream: the event stream of the template |
476 """ | 480 """ |
477 from genshi.template.loader import TemplateNotFound | 481 from genshi.template.loader import TemplateNotFound |
482 if inlined is None: | |
483 inlined = set((self.filepath,)) | |
478 | 484 |
479 for kind, data, pos in stream: | 485 for kind, data, pos in stream: |
480 if kind is SUB: | 486 if kind is SUB: |
481 directives = [] | 487 directives = [] |
482 substream = data[1] | 488 substream = data[1] |
483 for _, cls, value, namespaces, pos in sorted(data[0]): | 489 for _, cls, value, namespaces, pos in sorted(data[0]): |
484 directive, substream = cls.attach(self, substream, value, | 490 directive, substream = cls.attach(self, substream, value, |
485 namespaces, pos) | 491 namespaces, pos) |
486 if directive: | 492 if directive: |
487 directives.append(directive) | 493 directives.append(directive) |
488 substream = self._prepare(substream) | 494 substream = self._prepare(substream, inlined) |
489 if directives: | 495 if directives: |
490 yield kind, (directives, list(substream)), pos | 496 yield kind, (directives, list(substream)), pos |
491 else: | 497 else: |
492 for event in substream: | 498 for event in substream: |
493 yield event | 499 yield event |
494 else: | 500 else: |
495 if kind is INCLUDE: | 501 if kind is INCLUDE: |
496 href, cls, fallback = data | 502 href, cls, fallback = data |
497 if isinstance(href, basestring) and \ | 503 tmpl_inlined = False |
498 not getattr(self.loader, 'auto_reload', True): | 504 if (isinstance(href, basestring) and |
505 not getattr(self.loader, 'auto_reload', True)): | |
499 # If the path to the included template is static, and | 506 # If the path to the included template is static, and |
500 # auto-reloading is disabled on the template loader, | 507 # auto-reloading is disabled on the template loader, |
501 # the template is inlined into the stream | 508 # the template is inlined into the stream provided it |
509 # is not already in the stack of templates being | |
510 # processed. | |
511 tmpl = None | |
502 try: | 512 try: |
503 tmpl = self.loader.load(href, relative_to=pos[0], | 513 tmpl = self.loader.load(href, relative_to=pos[0], |
504 cls=cls or self.__class__) | 514 cls=cls or self.__class__) |
505 for event in tmpl.stream: | |
506 yield event | |
507 except TemplateNotFound: | 515 except TemplateNotFound: |
508 if fallback is None: | 516 if fallback is None: |
509 raise | 517 raise |
510 for event in self._prepare(fallback): | 518 if tmpl is not None: |
519 if tmpl.filepath not in inlined: | |
520 inlined.add(tmpl.filepath) | |
521 tmpl._prepare_self(inlined) | |
522 for event in tmpl.stream: | |
523 yield event | |
524 inlined.discard(tmpl.filepath) | |
525 tmpl_inlined = True | |
526 else: | |
527 for event in self._prepare(fallback, inlined): | |
511 yield event | 528 yield event |
529 tmpl_inlined = True | |
530 if tmpl_inlined: | |
512 continue | 531 continue |
513 elif fallback: | 532 if fallback: |
514 # Otherwise the include is performed at run time | 533 # Otherwise the include is performed at run time |
515 data = href, cls, list(self._prepare(fallback)) | 534 data = href, cls, list( |
516 | 535 self._prepare(fallback, inlined)) |
517 yield kind, data, pos | 536 yield kind, data, pos |
537 else: | |
538 yield kind, data, pos | |
518 | 539 |
519 def generate(self, *args, **kwargs): | 540 def generate(self, *args, **kwargs): |
520 """Apply the template to the given context data. | 541 """Apply the template to the given context data. |
521 | 542 |
522 Any keyword arguments are made available to the template as context | 543 Any keyword arguments are made available to the template as context |