changeset 439:9f11c745fac9 trunk

Add support for adding custom template filters by passing a custom callback function to the `TemplateLoader`. Closes #89 (see added unit test).
author cmlenz
date Mon, 02 Apr 2007 19:43:31 +0000
parents 2c38ec4e2dff
children 7884617bc941
files genshi/filters.py genshi/template/loader.py genshi/template/tests/loader.py
diffstat 3 files changed, 46 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/genshi/filters.py
+++ b/genshi/filters.py
@@ -62,11 +62,10 @@
             data = {}
         self.data = data
 
-    def __call__(self, stream, ctxt=None):
+    def __call__(self, stream):
         """Apply the filter to the given stream.
         
         :param stream: the markup event stream to filter
-        :param ctxt: the template context (unused)
         """
         in_form = in_select = in_option = in_textarea = False
         select_value = option_value = textarea_value = None
@@ -251,11 +250,10 @@
         self.uri_attrs = uri_attrs
         self.safe_schemes = safe_schemes
 
-    def __call__(self, stream, ctxt=None):
+    def __call__(self, stream):
         """Apply the filter to the given stream.
         
         :param stream: the markup event stream to filter
-        :param ctxt: the template context (unused)
         """
         waiting_for = None
 
--- a/genshi/template/loader.py
+++ b/genshi/template/loader.py
@@ -72,7 +72,8 @@
     >>> os.remove(path)
     """
     def __init__(self, search_path=None, auto_reload=False,
-                 default_encoding=None, max_cache_size=25, default_class=None):
+                 default_encoding=None, max_cache_size=25, default_class=None,
+                 callback=None):
         """Create the template laoder.
         
         :param search_path: a list of absolute path names that should be
@@ -86,6 +87,11 @@
                                cache
         :param default_class: the default `Template` subclass to use when
                               instantiating templates
+        :param callback: (optional) a callback function that is invoked after a
+                         template was initialized by this loader; the function
+                         is passed the template object as only argument. This
+                         callback can be used for example to add any desired
+                         filters to the template
         """
         from genshi.template.markup import MarkupTemplate
 
@@ -97,6 +103,9 @@
         self.auto_reload = auto_reload
         self.default_encoding = default_encoding
         self.default_class = default_class or MarkupTemplate
+        if callback is not None and not callable(callback):
+            raise TypeError('The "callback" parameter needs to be callable')
+        self.callback = callback
         self._cache = LRUCache(max_cache_size)
         self._mtime = {}
         self._lock = threading.Lock()
@@ -186,10 +195,12 @@
                             dirname = ''
                         tmpl = cls(fileobj, basedir=dirname, filename=filename,
                                    loader=self, encoding=encoding)
+                        if self.callback:
+                            self.callback(tmpl)
+                        self._cache[filename] = tmpl
+                        self._mtime[filename] = os.path.getmtime(filepath)
                     finally:
                         fileobj.close()
-                    self._cache[filename] = tmpl
-                    self._mtime[filename] = os.path.getmtime(filepath)
                     return tmpl
                 except IOError:
                     continue
--- a/genshi/template/tests/loader.py
+++ b/genshi/template/tests/loader.py
@@ -17,6 +17,7 @@
 import tempfile
 import unittest
 
+from genshi.core import TEXT
 from genshi.template.loader import TemplateLoader
 from genshi.template.markup import MarkupTemplate
 
@@ -189,6 +190,35 @@
         loader = TemplateLoader([self.dirname], default_encoding='utf-8')
         loader.load('tmpl.html', encoding='iso-8859-1')
 
+    def test_load_with_callback(self):
+        fileobj = open(os.path.join(self.dirname, 'tmpl.html'), 'w')
+        try:
+            fileobj.write("""<html>
+              <p>Hello</p>
+            </html>""")
+        finally:
+            fileobj.close()
+
+        def template_loaded(template):
+            def my_filter(stream, ctxt):
+                for kind, data, pos in stream:
+                    if kind is TEXT and data.strip():
+                        data = ', '.join([data, data.lower()])
+                    yield kind, data, pos
+            template.filters.insert(0, my_filter)
+
+        loader = TemplateLoader([self.dirname], callback=template_loaded)
+        tmpl = loader.load('tmpl.html')
+        self.assertEqual("""<html>
+              <p>Hello, hello</p>
+            </html>""", tmpl.generate().render())
+
+        # Make sure the filter is only added once
+        tmpl = loader.load('tmpl.html')
+        self.assertEqual("""<html>
+              <p>Hello, hello</p>
+            </html>""", tmpl.generate().render())
+
 
 def suite():
     suite = unittest.TestSuite()
Copyright (C) 2012-2017 Edgewall Software