Edgewall Software

Changeset 657


Ignore:
Timestamp:
Jun 29, 2007, 3:06:53 PM (16 years ago)
Author:
cmlenz
Message:

Implement static includes, which improves performance a bit when auto reloading is disabled.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/ChangeLog

    r654 r657  
    1414 * Support for Python code blocks in templates can now be disabled
    1515   (ticket #123).
     16 * Includes are now processed when the template is parsed if possible, but
     17   only if the template loader is not set to do automatic reloading. Included
     18   templates are basically inlined into the including template, which can
     19   speed up rendering of that template a bit.
    1620
    1721
  • trunk/doc/plugin.txt

    r654 r657  
    116116to enable this reloading (which is the default), or "no" to turn it off.
    117117
    118 .. note:: You may want to disable reloading in a production environment to gain
    119           a slight (and possible even negligible) improvement in loading
    120           performance, but then you'll have to manually restart the server
    121           process anytime the templates are updated.
     118You probably want to disable reloading in a production environment to improve
     119performance of both templating loading and the processing of includes. But
     120remember that you'll then have to manually restart the server process anytime
     121the templates are updated.
    122122
    123123``genshi.default_doctype``
  • trunk/genshi/template/base.py

    r654 r657  
    355355        :param stream: the event stream of the template
    356356        """
     357        from genshi.template.loader import TemplateNotFound
     358
    357359        for kind, data, pos in stream:
    358360            if kind is SUB:
     
    372374            else:
    373375                if kind is INCLUDE:
    374                     data = data[0], list(self._prepare(data[1]))
     376                    href, fallback = data
     377                    if isinstance(href, basestring) and \
     378                            not getattr(self.loader, 'auto_reload', True):
     379                        # If the path to the included template is static, and
     380                        # auto-reloading is disabled on the template loader,
     381                        # the template is inlined into the stream
     382                        try:
     383                            tmpl = self.loader.load(href, relative_to=pos[0],
     384                                                    cls=self.__class__)
     385                            for event in tmpl.stream:
     386                                yield event
     387                        except TemplateNotFound:
     388                            if fallback is None:
     389                                raise
     390                            for event in self._prepare(fallback):
     391                                yield event
     392                        continue
     393                    else:
     394                        # Otherwise the include is performed at run time
     395                        data = href, list(self._prepare(fallback))
     396
    375397                yield kind, data, pos
    376398
  • trunk/genshi/template/loader.py

    r654 r657  
    6969    >>> loader.load(os.path.basename(path)) is template
    7070    True
     71   
     72    The `auto_reload` option can be used to control whether a template should
     73    be automatically reloaded when the file it was loaded from has been
     74    changed. Disable this automatic reloading to improve performance.
    7175   
    7276    >>> os.remove(path)
     
    108112        elif isinstance(self.search_path, basestring):
    109113            self.search_path = [self.search_path]
     114
    110115        self.auto_reload = auto_reload
     116        """Whether templates should be reloaded when the underlying file is
     117        changed"""
     118
    111119        self.default_encoding = default_encoding
    112120        self.default_class = default_class or MarkupTemplate
     
    118126        self._cache = LRUCache(max_cache_size)
    119127        self._mtime = {}
    120         self._lock = threading.Lock()
     128        self._lock = threading.RLock()
    121129
    122130    def load(self, filename, relative_to=None, cls=None, encoding=None):
  • trunk/genshi/template/tests/markup.py

    r655 r657  
    450450            shutil.rmtree(dirname)
    451451
     452    def test_include_inlined(self):
     453        dirname = tempfile.mkdtemp(suffix='genshi_test')
     454        try:
     455            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
     456            try:
     457                file1.write("""<div>Included</div>""")
     458            finally:
     459                file1.close()
     460
     461            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
     462            try:
     463                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
     464                                     xmlns:py="http://genshi.edgewall.org/">
     465                  <xi:include href="tmpl1.html" />
     466                </html>""")
     467            finally:
     468                file2.close()
     469
     470            loader = TemplateLoader([dirname], auto_reload=False)
     471            tmpl = loader.load('tmpl2.html')
     472            # if not inlined the following would be 5
     473            self.assertEqual(7, len(tmpl.stream))
     474            self.assertEqual("""<html>
     475                  <div>Included</div>
     476                </html>""", tmpl.generate().render())
     477        finally:
     478            shutil.rmtree(dirname)
     479
     480    def test_include_inlined_in_loop(self):
     481        dirname = tempfile.mkdtemp(suffix='genshi_test')
     482        try:
     483            file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w')
     484            try:
     485                file1.write("""<div>Included $idx</div>""")
     486            finally:
     487                file1.close()
     488
     489            file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w')
     490            try:
     491                file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
     492                                     xmlns:py="http://genshi.edgewall.org/">
     493                  <xi:include href="tmpl1.html" py:for="idx in range(3)" />
     494                </html>""")
     495            finally:
     496                file2.close()
     497
     498            loader = TemplateLoader([dirname], auto_reload=False)
     499            tmpl = loader.load('tmpl2.html')
     500            self.assertEqual("""<html>
     501                  <div>Included 0</div><div>Included 1</div><div>Included 2</div>
     502                </html>""", tmpl.generate().render())
     503        finally:
     504            shutil.rmtree(dirname)
     505
    452506    def test_allow_exec_false(self):
    453507        xml = ("""<?python
Note: See TracChangeset for help on using the changeset viewer.