Skip to content

Commit e5f33d4

Browse files
committed
- 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
1 parent bdbbae0 commit e5f33d4

File tree

7 files changed

+69
-8
lines changed

7 files changed

+69
-8
lines changed

CHANGES

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ either one "#" sign or two for now; two is preferred going forward, i.e.
99
- UNDEFINED evaluates to False
1010
- improvement to scoping of "caller" variable when using <%call> tag
1111
- added lexer error for unclosed control-line (%) line
12-
12+
- added "preprocessor" argument to Template, TemplateLookup - is a single
13+
callable or list of callables which will be applied to the template text
14+
before lexing. given the text as an argument, returns the new text.
15+
- added mako.ext.preprocessors package, contains one preprocessor so far:
16+
'convert_comments', which will convert single # comments to the new ##
17+
format
18+
1319
0.1.2
1420
- fix to parsing of code/expression blocks to insure that non-ascii
1521
characters, combined with a template that indicates a non-standard

lib/mako/ext/preprocessors.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""preprocessing functions, used with the 'preprocessor' argument on Template, TemplateLookup"""
2+
3+
import re
4+
5+
def convert_comments(text):
6+
"""preprocess old style comments.
7+
8+
example:
9+
10+
from mako.ext.preprocessors import convert_comments
11+
t = Template(..., preprocessor=preprocess_comments)"""
12+
return re.sub(r'(?<=\n)\s*#[^#]', "##", text)
13+
14+
# TODO
15+
def create_tag(callable):
16+
"""given a callable, extract the *args and **kwargs, and produce a preprocessor
17+
that will parse for <%<funcname> <args>> and convert to an appropriate <%call> statement.
18+
19+
this allows any custom tag to be created which looks like a pure Mako-style tag."""
20+
raise NotImplementedError("Future functionality....")

lib/mako/lexer.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from mako.pygen import adjust_whitespace
1212

1313
class Lexer(object):
14-
def __init__(self, text, filename=None, input_encoding=None):
14+
def __init__(self, text, filename=None, input_encoding=None, preprocessor=None):
1515
self.text = text
1616
self.filename = filename
1717
self.template = parsetree.TemplateNode(self.filename)
@@ -22,6 +22,12 @@ def __init__(self, text, filename=None, input_encoding=None):
2222
self.tag = []
2323
self.control_line = []
2424
self.encoding = input_encoding
25+
if preprocessor is None:
26+
self.preprocessor = []
27+
elif not hasattr(preprocessor, '__iter__'):
28+
self.preprocessor = [preprocessor]
29+
else:
30+
self.preprocessor = preprocessor
2531

2632
def match(self, regexp, flags=None):
2733
"""match the given regular expression string and flags to the current text position.
@@ -95,6 +101,8 @@ def escape_code(self, text):
95101
return text
96102

97103
def parse(self):
104+
for preproc in self.preprocessor:
105+
self.text = preproc(self.text)
98106
parsed_encoding = self.match_encoding()
99107
if parsed_encoding:
100108
self.encoding = parsed_encoding

lib/mako/lookup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ def adjust_uri(self, uri, filename):
3737
return uri
3838

3939
class TemplateLookup(TemplateCollection):
40-
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):
40+
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):
4141
if isinstance(directories, basestring):
4242
directories = [directories]
4343
self.directories = [posixpath.normpath(d) for d in directories or []]
4444
self.module_directory = module_directory
4545
self.modulename_callable = modulename_callable
4646
self.filesystem_checks = filesystem_checks
4747
self.collection_size = collection_size
48-
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}
48+
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}
4949
if collection_size == -1:
5050
self.__collection = {}
5151
self._uri_cache = {}

lib/mako/template.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
class Template(object):
1818
"""a compiled template"""
19-
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):
19+
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):
2020
"""construct a new Template instance using either literal template text, or a previously loaded template module
2121
2222
text - textual template source, or None if a module is to be provided
@@ -41,6 +41,7 @@ def __init__(self, text=None, filename=None, uri=None, format_exceptions=False,
4141
self.default_filters = default_filters
4242
self.input_encoding = input_encoding
4343
self.imports = imports
44+
self.preprocessor = preprocessor
4445

4546
# if plain text, compile code in memory only
4647
if text is not None:
@@ -171,7 +172,7 @@ def _get_source(self):
171172

172173
def _compile_text(template, text, filename):
173174
identifier = template.module_id
174-
node = Lexer(text, filename, input_encoding=template.input_encoding).parse()
175+
node = Lexer(text, filename, input_encoding=template.input_encoding, preprocessor=template.preprocessor).parse()
175176
source = codegen.compile(node, template.uri, filename, default_filters=template.default_filters, imports=template.imports)
176177
cid = identifier
177178
module = imp.new_module(cid)
@@ -182,7 +183,7 @@ def _compile_text(template, text, filename):
182183
def _compile_module_file(template, text, filename, outputpath):
183184
identifier = template.module_id
184185
(dest, name) = tempfile.mkstemp()
185-
node = Lexer(text, filename, input_encoding=template.input_encoding).parse()
186+
node = Lexer(text, filename, input_encoding=template.input_encoding, preprocessor=template.preprocessor).parse()
186187
source = codegen.compile(node, template.uri, filename, default_filters=template.default_filters, imports=template.imports)
187188
os.write(dest, source)
188189
os.close(dest)

test/lexer.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from mako import exceptions
55
from util import flatten_result, result_lines
66
from mako.template import Template
7+
import re
78

89
class LexerTest(unittest.TestCase):
910
def test_text_and_tag(self):
@@ -376,6 +377,17 @@ def test_comments(self):
376377
"""
377378
nodes = Lexer(template).parse()
378379
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))])"""
380+
381+
def test_preprocess(self):
382+
def preproc(text):
383+
return re.sub(r'(?<=\n)\s*#[^#]', "##", text)
384+
template = """
385+
hi
386+
# old style comment
387+
# another comment
388+
"""
389+
nodes = Lexer(template, preprocessor=preproc).parse()
390+
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))])"""
379391

380392
if __name__ == '__main__':
381393
unittest.main()

test/template.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from mako.template import Template
44
from mako.lookup import TemplateLookup
5+
from mako.ext.preprocessors import convert_comments
56
import unittest, re, os
67
from util import flatten_result, result_lines
78

@@ -196,7 +197,20 @@ def get_modname(filename, uri):
196197
t2 = lookup.get_template('/subdir/modtest.html')
197198
assert t.module.__file__ == 'test_htdocs/foo/modtest.html.py'
198199
assert t2.module.__file__ == 'test_htdocs/subdir/foo/modtest.html.py'
199-
200+
201+
class PreprocessTest(unittest.TestCase):
202+
def test_old_comments(self):
203+
t = Template("""
204+
im a template
205+
# old style comment
206+
# more old style comment
207+
208+
## new style comment
209+
- # not a comment
210+
- ## not a comment
211+
""", preprocessor=convert_comments)
212+
213+
assert flatten_result(t.render()) == "im a template - # not a comment - ## not a comment"
200214

201215
if __name__ == '__main__':
202216
unittest.main()

0 commit comments

Comments
 (0)