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