- added "preprocessor" argument to Template, TemplateLookup - is a single
callable or list of callables which will be applied to the template text
before lexing. given the text as an argument, returns the new text.
- added mako.ext.preprocessors package, contains one preprocessor so far:
'convert_comments', which will convert single # comments to the new ##
format
diff --git a/CHANGES b/CHANGES
index 711b2a9..f160bc5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,7 +9,13 @@
- UNDEFINED evaluates to False
- improvement to scoping of "caller" variable when using <%call> tag
- added lexer error for unclosed control-line (%) line
-
+- added "preprocessor" argument to Template, TemplateLookup - is a single
+ callable or list of callables which will be applied to the template text
+ before lexing. given the text as an argument, returns the new text.
+- added mako.ext.preprocessors package, contains one preprocessor so far:
+ 'convert_comments', which will convert single # comments to the new ##
+ format
+
0.1.2
- fix to parsing of code/expression blocks to insure that non-ascii
characters, combined with a template that indicates a non-standard
diff --git a/lib/mako/ext/preprocessors.py b/lib/mako/ext/preprocessors.py
new file mode 100644
index 0000000..601ac0d
--- /dev/null
+++ b/lib/mako/ext/preprocessors.py
@@ -0,0 +1,20 @@
+"""preprocessing functions, used with the 'preprocessor' argument on Template, TemplateLookup"""
+
+import re
+
+def convert_comments(text):
+ """preprocess old style comments.
+
+ example:
+
+ from mako.ext.preprocessors import convert_comments
+ t = Template(..., preprocessor=preprocess_comments)"""
+ return re.sub(r'(?<=\n)\s*#[^#]', "##", text)
+
+# TODO
+def create_tag(callable):
+ """given a callable, extract the *args and **kwargs, and produce a preprocessor
+ that will parse for <%<funcname> <args>> and convert to an appropriate <%call> statement.
+
+ this allows any custom tag to be created which looks like a pure Mako-style tag."""
+ raise NotImplementedError("Future functionality....")
\ No newline at end of file
diff --git a/lib/mako/lexer.py b/lib/mako/lexer.py
index 0d9081d..9e0905f 100644
--- a/lib/mako/lexer.py
+++ b/lib/mako/lexer.py
@@ -11,7 +11,7 @@
from mako.pygen import adjust_whitespace
class Lexer(object):
- def __init__(self, text, filename=None, input_encoding=None):
+ def __init__(self, text, filename=None, input_encoding=None, preprocessor=None):
self.text = text
self.filename = filename
self.template = parsetree.TemplateNode(self.filename)
@@ -22,6 +22,12 @@
self.tag = []
self.control_line = []
self.encoding = input_encoding
+ if preprocessor is None:
+ self.preprocessor = []
+ elif not hasattr(preprocessor, '__iter__'):
+ self.preprocessor = [preprocessor]
+ else:
+ self.preprocessor = preprocessor
def match(self, regexp, flags=None):
"""match the given regular expression string and flags to the current text position.
@@ -95,6 +101,8 @@
return text
def parse(self):
+ for preproc in self.preprocessor:
+ self.text = preproc(self.text)
parsed_encoding = self.match_encoding()
if parsed_encoding:
self.encoding = parsed_encoding
diff --git a/lib/mako/lookup.py b/lib/mako/lookup.py
index 0ec01e1..b975ac6 100644
--- a/lib/mako/lookup.py
+++ b/lib/mako/lookup.py
@@ -37,7 +37,7 @@
return uri
class TemplateLookup(TemplateCollection):
- def __init__(self, directories=None, module_directory=None, filesystem_checks=True, collection_size=-1, format_exceptions=False, error_handler=None, output_encoding=None, cache_type=None, cache_dir=None, modulename_callable=None, default_filters=['unicode'], imports=None, input_encoding=None):
+ def __init__(self, directories=None, module_directory=None, filesystem_checks=True, collection_size=-1, format_exceptions=False, error_handler=None, output_encoding=None, cache_type=None, cache_dir=None, modulename_callable=None, default_filters=['unicode'], imports=None, input_encoding=None, preprocessor=None):
if isinstance(directories, basestring):
directories = [directories]
self.directories = [posixpath.normpath(d) for d in directories or []]
@@ -45,7 +45,7 @@
self.modulename_callable = modulename_callable
self.filesystem_checks = filesystem_checks
self.collection_size = collection_size
- self.template_args = {'format_exceptions':format_exceptions, 'error_handler':error_handler, 'output_encoding':output_encoding, 'input_encoding':input_encoding, 'module_directory':module_directory, 'cache_type':cache_type, 'cache_dir':cache_dir or module_directory, 'default_filters':default_filters, 'imports':imports}
+ self.template_args = {'format_exceptions':format_exceptions, 'error_handler':error_handler, 'output_encoding':output_encoding, 'input_encoding':input_encoding, 'module_directory':module_directory, 'cache_type':cache_type, 'cache_dir':cache_dir or module_directory, 'default_filters':default_filters, 'imports':imports, 'preprocessor':preprocessor}
if collection_size == -1:
self.__collection = {}
self._uri_cache = {}
diff --git a/lib/mako/template.py b/lib/mako/template.py
index de6ba1f..7b8608a 100644
--- a/lib/mako/template.py
+++ b/lib/mako/template.py
@@ -16,7 +16,7 @@
class Template(object):
"""a compiled template"""
- def __init__(self, text=None, filename=None, uri=None, format_exceptions=False, error_handler=None, lookup=None, output_encoding=None, module_directory=None, cache_type=None, cache_dir=None, module_filename=None, input_encoding=None, default_filters=['unicode'], imports=None):
+ def __init__(self, text=None, filename=None, uri=None, format_exceptions=False, error_handler=None, lookup=None, output_encoding=None, module_directory=None, cache_type=None, cache_dir=None, module_filename=None, input_encoding=None, default_filters=['unicode'], imports=None, preprocessor=None):
"""construct a new Template instance using either literal template text, or a previously loaded template module
text - textual template source, or None if a module is to be provided
@@ -41,6 +41,7 @@
self.default_filters = default_filters
self.input_encoding = input_encoding
self.imports = imports
+ self.preprocessor = preprocessor
# if plain text, compile code in memory only
if text is not None:
@@ -171,7 +172,7 @@
def _compile_text(template, text, filename):
identifier = template.module_id
- node = Lexer(text, filename, input_encoding=template.input_encoding).parse()
+ node = Lexer(text, filename, input_encoding=template.input_encoding, preprocessor=template.preprocessor).parse()
source = codegen.compile(node, template.uri, filename, default_filters=template.default_filters, imports=template.imports)
cid = identifier
module = imp.new_module(cid)
@@ -182,7 +183,7 @@
def _compile_module_file(template, text, filename, outputpath):
identifier = template.module_id
(dest, name) = tempfile.mkstemp()
- node = Lexer(text, filename, input_encoding=template.input_encoding).parse()
+ node = Lexer(text, filename, input_encoding=template.input_encoding, preprocessor=template.preprocessor).parse()
source = codegen.compile(node, template.uri, filename, default_filters=template.default_filters, imports=template.imports)
os.write(dest, source)
os.close(dest)
diff --git a/test/lexer.py b/test/lexer.py
index 8c76202..b12a756 100644
--- a/test/lexer.py
+++ b/test/lexer.py
@@ -4,6 +4,7 @@
from mako import exceptions
from util import flatten_result, result_lines
from mako.template import Template
+import re
class LexerTest(unittest.TestCase):
def test_text_and_tag(self):
@@ -376,6 +377,17 @@
"""
nodes = Lexer(template).parse()
assert repr(nodes) == r"""TemplateNode({}, [Text(u'\n<style>\n #someselector\n # other non comment stuff\n</style>\n', (1, 1)), Comment(u'a comment', (6, 1)), Text(u'\n# also not a comment\n\n', (7, 1)), Comment(u'this is a comment', (10, 1)), Text(u' \nthis is ## not a comment\n\n', (11, 1)), Comment(u' multiline\ncomment\n', (14, 1)), Text(u'\n\nhi\n', (16, 8))])"""
+
+ def test_preprocess(self):
+ def preproc(text):
+ return re.sub(r'(?<=\n)\s*#[^#]', "##", text)
+ template = """
+ hi
+ # old style comment
+# another comment
+"""
+ nodes = Lexer(template, preprocessor=preproc).parse()
+ assert repr(nodes) == r"""TemplateNode({}, [Text(u'\n hi\n', (1, 1)), Comment(u'old style comment', (3, 1)), Comment(u'another comment', (4, 1))])"""
if __name__ == '__main__':
unittest.main()
diff --git a/test/template.py b/test/template.py
index 2611e39..871b34f 100644
--- a/test/template.py
+++ b/test/template.py
@@ -2,6 +2,7 @@
from mako.template import Template
from mako.lookup import TemplateLookup
+from mako.ext.preprocessors import convert_comments
import unittest, re, os
from util import flatten_result, result_lines
@@ -196,7 +197,20 @@
t2 = lookup.get_template('/subdir/modtest.html')
assert t.module.__file__ == 'test_htdocs/foo/modtest.html.py'
assert t2.module.__file__ == 'test_htdocs/subdir/foo/modtest.html.py'
-
+
+class PreprocessTest(unittest.TestCase):
+ def test_old_comments(self):
+ t = Template("""
+ im a template
+# old style comment
+ # more old style comment
+
+ ## new style comment
+ - # not a comment
+ - ## not a comment
+""", preprocessor=convert_comments)
+
+ assert flatten_result(t.render()) == "im a template - # not a comment - ## not a comment"
if __name__ == '__main__':
unittest.main()