changeset 769:834e8fd2d822

Includes from templates loaded via an absolute path now include the correct file in nested directories as long if no search path has been configured. Closes #240.
author cmlenz
date Tue, 01 Jul 2008 10:35:01 +0000
parents 950667d42a0a
children b4c973fbe6f5
files ChangeLog doc/plugin.txt genshi/template/loader.py genshi/template/plugin.py genshi/template/tests/loader.py
diffstat 5 files changed, 81 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,9 @@
    not directly a string, but rather something like an instance of the
    `LazyProxy` class in Babel (ticket #145).
  * Fix problem with match templates incorrectly being applied multiple times.
+ * Includes from templates loaded via an absolute path now include the correct
+   file in nested directories as long if no search path has been configured
+   (ticket #240).
 
 
 Version 0.5
--- a/doc/plugin.txt
+++ b/doc/plugin.txt
@@ -22,12 +22,11 @@
 Introduction
 ============
 
-Most Python web frameworks (with the notable exception of Django_) support
-a variety of different templating engines through the `Template Engine Plugin
-API`_, which was first developed by the Buffet_ and TurboGears_ projects.
+Some Python web frameworks support a variety of different templating engines
+through the `Template Engine Plugin API`_, which was first developed by the
+Buffet_ and TurboGears_ projects.
 
 .. _`Template Engine Plugin API`: http://docs.turbogears.org/1.0/TemplatePlugins
-.. _`Django`: http://www.djangoproject.com/
 .. _`Buffet`: http://projects.dowski.com/projects/buffet
 .. _`TurboGears`: http://www.turbogears.org/
 
@@ -72,8 +71,31 @@
 format when you want to produce an Atom feed or other XML content.
 
 
+Template Paths
+--------------
+
+How you specify template paths depends on whether you have a `search path`_ set
+up or not. The search path is a list of directories that Genshi should load
+templates from. Now when you request a template using a relative path such as
+``mytmpl.html`` or ``foo/mytmpl.html``, Genshi will look for that file in the
+directories on the search path.
+
+For mostly historical reasons, the Genshi template engine plugin uses a
+different approach when you **haven't** configured the template search path:
+you now load templates using *dotted notation*, for example ``mytmpl`` or
+``foo.mytmpl``.  Note how you've lost the ability to explicitly specify the
+file extension: you now have to use ``.html`` for markup templates, and
+``.txt`` for text templates.
+
+Using the search path is recommended for a number of reasons: First, it's
+the native Genshi model and is thus more robust and better supported.
+Second, a search path gives you much more flexibility for organizing your
+application templates. And as noted above, you aren't forced to use hardcoded
+filename extensions for your template files.
+
+
 Extra Implicit Objects
-======================
+----------------------
 
 The "genshi-markup" template engine plugin adds some extra functions that are
 made available to all templates implicitly, namely:
@@ -230,6 +252,8 @@
 In the version of Genshi, the default is to use the old syntax for
 backwards-compatibility, but that will change in a future release.
 
+.. _`search path`:
+
 ``genshi.search_path``
 ----------------------
 A colon-separated list of file-system path names that the template loader should
--- a/genshi/template/loader.py
+++ b/genshi/template/loader.py
@@ -163,8 +163,14 @@
         """
         if cls is None:
             cls = self.default_class
-        if relative_to and not os.path.isabs(relative_to):
+        search_path = self.search_path
+
+        # Make the filename relative to the template file its being loaded
+        # from, but only if that file is specified as a relative path, or no
+        # search path has been set up
+        if relative_to and (not search_path or not os.path.isabs(relative_to)):
             filename = os.path.join(os.path.dirname(relative_to), filename)
+
         filename = os.path.normpath(filename)
         cachekey = filename
 
@@ -181,7 +187,6 @@
             except (KeyError, OSError):
                 pass
 
-            search_path = self.search_path
             isabs = False
 
             if os.path.isabs(filename):
--- a/genshi/template/plugin.py
+++ b/genshi/template/plugin.py
@@ -16,8 +16,6 @@
 CherryPy/Buffet.
 """
 
-from pkg_resources import resource_filename
-
 from genshi.input import ET, HTML, XML
 from genshi.output import DocType
 from genshi.template.base import Template
@@ -91,6 +89,7 @@
         if self.use_package_naming:
             divider = templatename.rfind('.')
             if divider >= 0:
+                from pkg_resources import resource_filename
                 package = templatename[:divider]
                 basename = templatename[divider + 1:] + self.extension
                 templatename = resource_filename(package, basename)
--- a/genshi/template/tests/loader.py
+++ b/genshi/template/tests/loader.py
@@ -261,6 +261,47 @@
             </html>""", tmpl1.generate().render())
         assert 'tmpl2.html' in loader._cache
 
+    def test_abspath_include_caching_without_search_path(self):
+        file1 = open(os.path.join(self.dirname, 'tmpl1.html'), 'w')
+        try:
+            file1.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
+              <xi:include href="tmpl2.html" />
+            </html>""")
+        finally:
+            file1.close()
+
+        file2 = open(os.path.join(self.dirname, 'tmpl2.html'), 'w')
+        try:
+            file2.write("""<div>Included</div>""")
+        finally:
+            file2.close()
+
+        os.mkdir(os.path.join(self.dirname, 'sub'))
+        file3 = open(os.path.join(self.dirname, 'sub', 'tmpl1.html'), 'w')
+        try:
+            file3.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude">
+              <xi:include href="tmpl2.html" />
+            </html>""")
+        finally:
+            file3.close()
+
+        file4 = open(os.path.join(self.dirname, 'sub', 'tmpl2.html'), 'w')
+        try:
+            file4.write("""<div>Included from sub</div>""")
+        finally:
+            file4.close()
+
+        loader = TemplateLoader()
+        tmpl1 = loader.load(os.path.join(self.dirname, 'tmpl1.html'))
+        self.assertEqual("""<html>
+              <div>Included</div>
+            </html>""", tmpl1.generate().render())
+        tmpl2 = loader.load(os.path.join(self.dirname, 'sub', 'tmpl1.html'))
+        self.assertEqual("""<html>
+              <div>Included from sub</div>
+            </html>""", tmpl2.generate().render())
+        assert 'tmpl2.html' not in loader._cache
+
     def test_load_with_default_encoding(self):
         f = open(os.path.join(self.dirname, 'tmpl.html'), 'w')
         try:
Copyright (C) 2012-2017 Edgewall Software