Mercurial > genshi > mirror
changeset 548:1cc1afc39176 trunk
Implement static includes, which improves performance a bit when auto reloading is disabled.
author | cmlenz |
---|---|
date | Fri, 29 Jun 2007 13:06:53 +0000 |
parents | 93b2a5792cfc |
children | 7214c1bdb383 |
files | ChangeLog doc/plugin.txt genshi/template/base.py genshi/template/loader.py genshi/template/tests/markup.py |
diffstat | 5 files changed, 94 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,10 @@ which allow matching against regular expressions. * Support for Python code blocks in templates can now be disabled (ticket #123). + * Includes are now processed when the template is parsed if possible, but + only if the template loader is not set to do automatic reloading. Included + templates are basically inlined into the including template, which can + speed up rendering of that template a bit. Version 0.4.3
--- a/doc/plugin.txt +++ b/doc/plugin.txt @@ -115,10 +115,10 @@ files, and automatically reload them if they have been changed. Specify "yes" to enable this reloading (which is the default), or "no" to turn it off. -.. note:: You may want to disable reloading in a production environment to gain - a slight (and possible even negligible) improvement in loading - performance, but then you'll have to manually restart the server - process anytime the templates are updated. +You probably want to disable reloading in a production environment to improve +performance of both templating loading and the processing of includes. But +remember that you'll then have to manually restart the server process anytime +the templates are updated. ``genshi.default_doctype`` --------------------------
--- a/genshi/template/base.py +++ b/genshi/template/base.py @@ -354,6 +354,8 @@ :param stream: the event stream of the template """ + from genshi.template.loader import TemplateNotFound + for kind, data, pos in stream: if kind is SUB: directives = [] @@ -371,7 +373,27 @@ yield event else: if kind is INCLUDE: - data = data[0], list(self._prepare(data[1])) + href, fallback = data + if isinstance(href, basestring) and \ + not getattr(self.loader, 'auto_reload', True): + # If the path to the included template is static, and + # auto-reloading is disabled on the template loader, + # the template is inlined into the stream + try: + tmpl = self.loader.load(href, relative_to=pos[0], + cls=self.__class__) + for event in tmpl.stream: + yield event + except TemplateNotFound: + if fallback is None: + raise + for event in self._prepare(fallback): + yield event + continue + else: + # Otherwise the include is performed at run time + data = href, list(self._prepare(fallback)) + yield kind, data, pos def generate(self, *args, **kwargs):
--- a/genshi/template/loader.py +++ b/genshi/template/loader.py @@ -69,6 +69,10 @@ >>> loader.load(os.path.basename(path)) is template True + The `auto_reload` option can be used to control whether a template should + be automatically reloaded when the file it was loaded from has been + changed. Disable this automatic reloading to improve performance. + >>> os.remove(path) """ def __init__(self, search_path=None, auto_reload=False, @@ -107,7 +111,11 @@ self.search_path = [] elif isinstance(self.search_path, basestring): self.search_path = [self.search_path] + self.auto_reload = auto_reload + """Whether templates should be reloaded when the underlying file is + changed""" + self.default_encoding = default_encoding self.default_class = default_class or MarkupTemplate self.variable_lookup = variable_lookup @@ -117,7 +125,7 @@ self.callback = callback self._cache = LRUCache(max_cache_size) self._mtime = {} - self._lock = threading.Lock() + self._lock = threading.RLock() def load(self, filename, relative_to=None, cls=None, encoding=None): """Load the template with the given name.
--- a/genshi/template/tests/markup.py +++ b/genshi/template/tests/markup.py @@ -449,6 +449,60 @@ finally: shutil.rmtree(dirname) + def test_include_inlined(self): + dirname = tempfile.mkdtemp(suffix='genshi_test') + try: + file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w') + try: + file1.write("""<div>Included</div>""") + finally: + file1.close() + + file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w') + try: + file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude" + xmlns:py="http://genshi.edgewall.org/"> + <xi:include href="tmpl1.html" /> + </html>""") + finally: + file2.close() + + loader = TemplateLoader([dirname], auto_reload=False) + tmpl = loader.load('tmpl2.html') + # if not inlined the following would be 5 + self.assertEqual(7, len(tmpl.stream)) + self.assertEqual("""<html> + <div>Included</div> + </html>""", tmpl.generate().render()) + finally: + shutil.rmtree(dirname) + + def test_include_inlined_in_loop(self): + dirname = tempfile.mkdtemp(suffix='genshi_test') + try: + file1 = open(os.path.join(dirname, 'tmpl1.html'), 'w') + try: + file1.write("""<div>Included $idx</div>""") + finally: + file1.close() + + file2 = open(os.path.join(dirname, 'tmpl2.html'), 'w') + try: + file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude" + xmlns:py="http://genshi.edgewall.org/"> + <xi:include href="tmpl1.html" py:for="idx in range(3)" /> + </html>""") + finally: + file2.close() + + loader = TemplateLoader([dirname], auto_reload=False) + tmpl = loader.load('tmpl2.html') + self.assertEqual("""<html> + <div>Included 0</div><div>Included 1</div><div>Included 2</div> + </html>""", tmpl.generate().render()) + finally: + shutil.rmtree(dirname) + def test_allow_exec_false(self): xml = ("""<?python title = "A Genshi Template"