Commit 3dd53c1a by Chris Jerdonek

Addressed issue #55: Add to Template() support for "encoding" and "errors"

Added two keyword arguments to Template.__init__(): "default_encoding" and
"decode_errors".  These are passed internally to unicode() as the "encoding"
and "errors" arguments when converting strings of type str to unicode.
parent ffd68e1f
...@@ -5,9 +5,10 @@ This module provides a Template class. ...@@ -5,9 +5,10 @@ This module provides a Template class.
""" """
import re
import cgi import cgi
import collections import collections
import re
import sys
from .context import Context from .context import Context
from .loader import Loader from .loader import Loader
...@@ -60,7 +61,8 @@ class Template(object): ...@@ -60,7 +61,8 @@ class Template(object):
modifiers = Modifiers() modifiers = Modifiers()
def __init__(self, template=None, load_template=None, output_encoding=None, escape=None): def __init__(self, template=None, load_template=None, output_encoding=None, escape=None,
default_encoding=None, decode_errors='strict'):
""" """
Construct a Template instance. Construct a Template instance.
...@@ -89,18 +91,35 @@ class Template(object): ...@@ -89,18 +91,35 @@ class Template(object):
importable and cgi.escape otherwise. To disable escaping entirely, importable and cgi.escape otherwise. To disable escaping entirely,
one can pass `lambda s: s` as the escape function, for example. one can pass `lambda s: s` as the escape function, for example.
default_encoding: the name of the encoding to use when converting
to unicode any strings of type `str` encountered during the
rendering process. The name will be passed as the "encoding"
argument to the built-in function unicode(). Defaults to the
encoding name returned by sys.getdefaultencoding().
decode_errors: the string to pass as the "errors" argument to the
built-in function unicode() when converting to unicode any
strings of type `str` encountered during the rendering process.
Defaults to "strict".
""" """
if load_template is None: if load_template is None:
loader = Loader() loader = Loader()
load_template = loader.load_template load_template = loader.load_template
if default_encoding is None:
default_encoding = sys.getdefaultencoding()
if escape is None: if escape is None:
escape = markupsafe.escape if markupsafe else cgi.escape escape = markupsafe.escape if markupsafe else cgi.escape
literal = markupsafe.Markup if markupsafe else unicode literal = markupsafe.Markup if markupsafe else unicode
self._literal = literal
self.decode_errors = decode_errors
self.default_encoding = default_encoding
self.escape = escape self.escape = escape
self.literal = literal
self.load_template = load_template self.load_template = load_template
self.output_encoding = output_encoding self.output_encoding = output_encoding
self.template = template self.template = template
...@@ -112,6 +131,31 @@ class Template(object): ...@@ -112,6 +131,31 @@ class Template(object):
s = unicode(s) s = unicode(s)
return self.escape(s) return self.escape(s)
def escape(self, u):
"""
Escape a unicode string, and return it.
This function is initialized as the escape function that was passed
to the Template class's constructor when this instance was
constructed. See the constructor docstring for more information.
"""
pass
def literal(self, s):
"""
Convert the given string to a unicode string, without escaping it.
This function internally calls the built-in function unicode() and
passes it the default_encoding and decode_errors attributes for this
Template instance. If markupsafe was importable when loading this
module, this function returns an instance of the class
markupsafe.Markup (which subclasses unicode).
"""
return self._literal(s, self.default_encoding, self.decode_errors)
def _initialize_context(self, context, **kwargs): def _initialize_context(self, context, **kwargs):
""" """
Initialize the context attribute. Initialize the context attribute.
......
...@@ -6,6 +6,7 @@ Unit tests of template.py. ...@@ -6,6 +6,7 @@ Unit tests of template.py.
""" """
import codecs import codecs
import sys
import unittest import unittest
from pystache import template from pystache import template
...@@ -55,6 +56,92 @@ class TemplateTestCase(unittest.TestCase): ...@@ -55,6 +56,92 @@ class TemplateTestCase(unittest.TestCase):
template = Template(escape=escape) template = Template(escape=escape)
self.assertEquals(template.escape("bar"), "foobar") self.assertEquals(template.escape("bar"), "foobar")
def test_init__default_encoding__default(self):
"""
Check the default value.
"""
template = Template()
self.assertEquals(template.default_encoding, sys.getdefaultencoding())
def test_init__default_encoding(self):
"""
Check that the constructor sets the attribute correctly.
"""
template = Template(default_encoding="foo")
self.assertEquals(template.default_encoding, "foo")
def test_init__decode_errors__default(self):
"""
Check the default value.
"""
template = Template()
self.assertEquals(template.decode_errors, 'strict')
def test_init__decode_errors(self):
"""
Check that the constructor sets the attribute correctly.
"""
template = Template(decode_errors="foo")
self.assertEquals(template.decode_errors, "foo")
def test_literal(self):
template = Template()
actual = template.literal("abc")
self.assertEquals(actual, "abc")
self.assertEquals(type(actual), unicode)
def test_literal__default_encoding(self):
template = Template()
template.default_encoding = "utf-8"
actual = template.literal("é")
self.assertEquals(actual, u"é")
def test_literal__default_encoding__error(self):
template = Template()
template.default_encoding = "ascii"
self.assertRaises(UnicodeDecodeError, template.literal, "é")
def test_literal__decode_errors(self):
template = Template()
template.default_encoding = "ascii"
s = "é"
template.decode_errors = "strict"
self.assertRaises(UnicodeDecodeError, template.literal, s)
template.decode_errors = "replace"
actual = template.literal(s)
# U+FFFD is the official Unicode replacement character.
self.assertEquals(actual, u'\ufffd\ufffd')
def test_literal__with_markupsafe(self):
if not self._was_markupsafe_imported():
# Then we cannot test this case.
return
self._restore_markupsafe()
_template = Template()
_template.default_encoding = "utf_8"
# Check the standard case.
actual = _template.literal("abc")
self.assertEquals(actual, "abc")
self.assertEquals(type(actual), template.markupsafe.Markup)
s = "é"
# Check that markupsafe respects default_encoding.
self.assertEquals(_template.literal(s), u"é")
_template.default_encoding = "ascii"
self.assertRaises(UnicodeDecodeError, _template.literal, s)
# Check that markupsafe respects decode_errors.
_template.decode_errors = "replace"
self.assertEquals(_template.literal(s), u'\ufffd\ufffd')
def test_render__unicode(self): def test_render__unicode(self):
template = Template(u'foo') template = Template(u'foo')
actual = template.render() actual = template.render()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment