From d4a1fc689c081fc96070199b54933798672f4cda Mon Sep 17 00:00:00 2001 From: Mike Bayer <mike_mp@zzzcomputing.com> Date: Tue, 21 Nov 2006 18:30:08 +0000 Subject: [PATCH] some thought given to unicode... --- lib/mako/codegen.py | 3 ++- lib/mako/template.py | 22 +++++++++++++++++----- lib/mako/util.py | 17 +++++++++++++++-- test/component.py | 1 + test/template.py | 18 ++++++++++++++++++ 5 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 test/template.py diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py index 56b0048..12bc424 100644 --- a/lib/mako/codegen.py +++ b/lib/mako/codegen.py @@ -7,6 +7,7 @@ """provides the Compiler object for generating module source code.""" import time +import re from mako.pygen import PythonPrinter from mako import util, ast, parsetree @@ -17,7 +18,7 @@ class Compiler(object): self.node = node self.filename = filename def render(self): - buf = util.StringIO() + buf = util.FastEncodingBuffer() printer = PythonPrinter(buf) # module-level names, python code diff --git a/lib/mako/template.py b/lib/mako/template.py index 562495d..d6e40d3 100644 --- a/lib/mako/template.py +++ b/lib/mako/template.py @@ -23,7 +23,7 @@ class _ModuleMarker(object): class Template(object): """a compiled template""" - def __init__(self, text=None, module=None, identifier=None, filename=None, format_exceptions=True, error_handler=None, lookup=None): + def __init__(self, text=None, module=None, identifier=None, filename=None, format_exceptions=False, error_handler=None, lookup=None, output_encoding=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 @@ -53,6 +53,7 @@ class Template(object): self.format_exceptions = format_exceptions self.error_handler = error_handler self.lookup = lookup + self.output_encoding = output_encoding _modules[module.__name__] = _ModuleMarker(module) source = property(lambda self:_get_template_source(self.callable_), doc="""return the template source code for this Template.""") @@ -61,11 +62,17 @@ class Template(object): def render(self, *args, **data): """render the output of this template as a string. + if the template specifies an output encoding, the string will be encoded accordingly, else the output + is raw (raw output uses cStringIO and can't handle multibyte characters). a Context object is created corresponding to the given data. Arguments that are explictly declared by this template's internal rendering method are also pulled from the given *args, **data members.""" - return _render(self, self.callable_, *args, **data) + return _render(self, self.callable_, args, data) + def render_unicode(self, *args, **data): + """render the output of this template as a unicode object.""" + return _render(self, self.callable_, args, data, as_unicode=True) + def render_context(self, context, *args, **kwargs): """render this Template with the given context. @@ -93,10 +100,15 @@ def _compile_text(text, identifier, filename): code = compile(source, filename or cid, 'exec') exec code in module.__dict__, module.__dict__ return (source, module) - -def _render(template, callable_, *args, **data): + +def _render(template, callable_, args, data, as_unicode=False): """given a Template and a callable_ from that template, create a Context and return the string output.""" - buf = util.StringIO() + if as_unicode: + buf = util.FastEncodingBuffer() + elif template.output_encoding: + buf = util.FastEncodingBuffer(template.output_encoding) + else: + buf = util.StringIO() context = Context(template, buf, **data) kwargs = {} argspec = inspect.getargspec(callable_) diff --git a/lib/mako/util.py b/lib/mako/util.py index 1d665fd..0560d8a 100644 --- a/lib/mako/util.py +++ b/lib/mako/util.py @@ -13,6 +13,19 @@ except: try: from cStringIO import StringIO except: - from StringIO import StringIO - + from StringIO import StringIO + + +class FastEncodingBuffer(object): + """a very rudimentary buffer that is faster than StringIO, but doesnt crash on unicode data like cStringIO.""" + def __init__(self, encoding=None): + self.data = [] + self.encoding = encoding + def write(self, text): + self.data.append(text) + def getvalue(self): + if self.encoding: + return u''.join(self.data).encode(self.encoding) + else: + return u''.join(self.data) diff --git a/test/component.py b/test/component.py index f265b85..834e3cc 100644 --- a/test/component.py +++ b/test/component.py @@ -13,6 +13,7 @@ class ComponentTest(unittest.TestCase): </%component> """) + print template.code assert template.render(variable='hi').strip() == """hello mycomp hi""" def test_component_blankargs(self): diff --git a/test/template.py b/test/template.py new file mode 100644 index 0000000..c7aa5e5 --- /dev/null +++ b/test/template.py @@ -0,0 +1,18 @@ +# -*- encoding: utf-8 -*- + +from mako.template import Template +import unittest +from util import flatten_result + +class EncodingTest(unittest.TestCase): + def test_unicode(self): + template = Template(u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petit voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + assert template.render_unicode() == u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petit voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""" + + def test_unicode_arg(self): + val = u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petit voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""" + template = Template("${val}") + assert template.render_unicode(val=val) == u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petit voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""" + +if __name__ == '__main__': + unittest.main() -- GitLab