# HG changeset patch # User cmlenz # Date 1183122413 0 # Node ID 1cc1afc391764ef9415d2d098e59fb1e44134462 # Parent 93b2a5792cfc55223587b978bd020dfb06ce1f33 Implement static includes, which improves performance a bit when auto reloading is disabled. diff --git a/ChangeLog b/ChangeLog --- 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 diff --git a/doc/plugin.txt b/doc/plugin.txt --- 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`` -------------------------- diff --git a/genshi/template/base.py b/genshi/template/base.py --- 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): diff --git a/genshi/template/loader.py b/genshi/template/loader.py --- 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. diff --git a/genshi/template/tests/markup.py b/genshi/template/tests/markup.py --- 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("""