# HG changeset patch # User cmlenz # Date 1214908977 0 # Node ID c290dc5a68137513282b40d7f4e2cf61541c04f4 # Parent f7682ced27778af01373b79d81627b9d92fdcaf3 Ported [894] and [895] back to 0.5.x branch. diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,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 diff --git a/doc/plugin.txt b/doc/plugin.txt --- 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 diff --git a/genshi/__init__.py b/genshi/__init__.py --- a/genshi/__init__.py +++ b/genshi/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2006-2007 Edgewall Software +# Copyright (C) 2006-2008 Edgewall Software # All rights reserved. # # This software is licensed as described in the file COPYING, which @@ -21,9 +21,13 @@ __docformat__ = 'restructuredtext en' try: - __version__ = __import__('pkg_resources').get_distribution('Genshi').version + from pkg_resources import get_distribution, ResolutionError + try: + __version__ = get_distribution('Genshi').version + except ResolutionError: + __version__ = None # unknown except ImportError: - pass + __version__ = None # unknown from genshi.core import * from genshi.input import ParseError, XML, HTML diff --git a/genshi/template/loader.py b/genshi/template/loader.py --- 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): diff --git a/genshi/template/plugin.py b/genshi/template/plugin.py --- 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) diff --git a/genshi/template/tests/loader.py b/genshi/template/tests/loader.py --- a/genshi/template/tests/loader.py +++ b/genshi/template/tests/loader.py @@ -261,6 +261,47 @@ """, 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(""" + + """) + finally: + file1.close() + + file2 = open(os.path.join(self.dirname, 'tmpl2.html'), 'w') + try: + file2.write("""
Included
""") + 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(""" + + """) + finally: + file3.close() + + file4 = open(os.path.join(self.dirname, 'sub', 'tmpl2.html'), 'w') + try: + file4.write("""
Included from sub
""") + finally: + file4.close() + + loader = TemplateLoader() + tmpl1 = loader.load(os.path.join(self.dirname, 'tmpl1.html')) + self.assertEqual(""" +
Included
+ """, tmpl1.generate().render()) + tmpl2 = loader.load(os.path.join(self.dirname, 'sub', 'tmpl1.html')) + self.assertEqual(""" +
Included from sub
+ """, 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: