Commit 3f3f2a96 by Chris Jerdonek

Merge branch 'issue-102-support-python3' into 'development'

Still more work to do: about 14 failing tests and still need to wire up
the spec tests and README doctests.
parents 844ebdbc 642cade9
......@@ -51,8 +51,8 @@ Use It
::
>>> import pystache
>>> pystache.render('Hi {{person}}!', {'person': 'Mom'})
u'Hi Mom!'
>>> print pystache.render('Hi {{person}}!', {'person': 'Mom'})
Hi Mom!
You can also create dedicated view classes to hold your view logic.
......@@ -75,8 +75,8 @@ Then your template, say_hello.mustache::
Pull it together::
>>> renderer = pystache.Renderer()
>>> renderer.render(hello)
u'Hello, Pizza!'
>>> print renderer.render(hello)
Hello, Pizza!
Unicode Handling
......@@ -161,8 +161,8 @@ Author
::
>>> context = { 'author': 'Chris Wanstrath', 'email': 'chris@ozmm.org' }
>>> pystache.render("{{author}} :: {{email}}", context)
u'Chris Wanstrath :: chris@ozmm.org'
>>> print pystache.render("{{author}} :: {{email}}", context)
Chris Wanstrath :: chris@ozmm.org
.. _ctemplate: http://code.google.com/p/google-ctemplate/
......
# coding: utf-8
"""
Exposes common functions.
"""
# This function was designed to be portable across Python versions -- both
# with older versions and with Python 3 after applying 2to3.
def read(path):
"""
Return the contents of a text file as a byte string.
"""
# Opening in binary mode is necessary for compatibility across Python
# 2 and 3. In both Python 2 and 3, open() defaults to opening files in
# text mode. However, in Python 2, open() returns file objects whose
# read() method returns byte strings (strings of type `str` in Python 2),
# whereas in Python 3, the file object returns unicode strings (strings
# of type `str` in Python 3).
f = open(path, 'rb')
# We avoid use of the with keyword for Python 2.4 support.
try:
return f.read()
finally:
f.close()
......@@ -5,11 +5,16 @@ Defines a Context class to represent mustache(5)'s notion of context.
"""
class NotFound(object): pass
# This equals '__builtin__' in Python 2 and 'builtins' in Python 3.
_BUILTIN_MODULE = type(0).__module__
# We use this private global variable as a return value to represent a key
# not being found on lookup. This lets us distinguish between the case
# of a key's value being None with the case of a key not being found --
# without having to rely on exceptions (e.g. KeyError) for flow control.
class NotFound(object):
pass
_NOT_FOUND = NotFound()
......@@ -34,7 +39,7 @@ def _get_value(item, key):
# (e.g. catching KeyError).
if key in item:
return item[key]
elif type(item).__module__ != '__builtin__':
elif type(item).__module__ != _BUILTIN_MODULE:
# Then we consider the argument an "object" for the purposes of
# the spec.
#
......
......@@ -8,7 +8,12 @@ does not otherwise specify a value.
"""
import cgi
try:
# Python 3.2 deprecates cgi.escape() and adds the html module as a replacement.
import html
except ImportError:
import cgi as html
import os
import sys
......@@ -39,12 +44,14 @@ SEARCH_DIRS = [os.curdir] # i.e. ['.']
# rendering templates (e.g. for tags enclosed in double braces).
# Only unicode strings will be passed to this function.
#
# The quote=True argument causes double quotes to be escaped,
# but not single quotes:
# The quote=True argument causes double quotes to be escaped in Python 2,
# but not single quotes, and both double quotes and single quotes to be
# escaped in Python 3:
#
# http://docs.python.org/dev/library/html.html#html.escape
# http://docs.python.org/library/cgi.html#cgi.escape
#
TAG_ESCAPE = lambda u: cgi.escape(u, quote=True)
TAG_ESCAPE = lambda u: html.escape(u, quote=True)
# The default template extension.
TEMPLATE_EXTENSION = 'mustache'
......@@ -8,6 +8,7 @@ This module provides a Loader class for locating and reading templates.
import os
import sys
from pystache import common
from pystache import defaults
from pystache.locator import Locator
......@@ -106,17 +107,12 @@ class Loader(object):
Read the template at the given path, and return it as a unicode string.
"""
# We avoid use of the with keyword for Python 2.4 support.
f = open(path, 'r')
try:
text = f.read()
finally:
f.close()
b = common.read(path)
if encoding is None:
encoding = self.file_encoding
return self.unicode(text, encoding)
return self.unicode(b, encoding)
# TODO: unit-test this method.
def load_name(self, name):
......
......@@ -131,7 +131,7 @@ class Parser(object):
if tag_type == '/':
if tag_key != section_key:
raise ParsingError("Section end tag mismatch: %s != %s" % (repr(tag_key), repr(section_key)))
raise ParsingError("Section end tag mismatch: %s != %s" % (tag_key, section_key))
return ParsedTemplate(parse_tree), template[start_index:match_index], end_index
......
......@@ -55,7 +55,7 @@ class RenderEngine(object):
this class will not pass tag values to literal prior to passing
them to this function. This allows for more flexibility,
for example using a custom escape function that handles
incoming strings of type markupssafe.Markup differently
incoming strings of type markupsafe.Markup differently
from plain unicode strings.
"""
......@@ -167,9 +167,28 @@ class RenderEngine(object):
# TODO: should we check the arity?
template = data(template)
parsed_template = self._parse(template, delimiters=delims)
data = [ data ]
elif not hasattr(data, '__iter__') or isinstance(data, dict):
data = [ data ]
data = [data]
else:
# The cleanest, least brittle way of determining whether
# something supports iteration is by trying to call iter() on it:
#
# http://docs.python.org/library/functions.html#iter
#
# It is not sufficient, for example, to check whether the item
# implements __iter__ () (the iteration protocol). There is
# also __getitem__() (the sequence protocol). In Python 2,
# strings do not implement __iter__(), but in Python 3 they do.
try:
iter(data)
except TypeError:
# Then the value does not support iteration.
data = [data]
else:
# We treat the value as a list (but do not treat strings
# and dicts as lists).
if isinstance(data, (basestring, dict)):
data = [data]
# Otherwise, leave it alone.
parts = []
for element in data:
......
......@@ -9,7 +9,7 @@ from pystache import defaults
from pystache.context import Context
from pystache.loader import Loader
from pystache.renderengine import RenderEngine
from pystache.spec_loader import SpecLoader
from pystache.specloader import SpecLoader
from pystache.template_spec import TemplateSpec
......@@ -64,10 +64,10 @@ class Renderer(object):
this class will only pass it unicode strings. The constructor
assigns this function to the constructed instance's escape()
method.
The argument defaults to `cgi.escape(s, quote=True)`. To
disable escaping entirely, one can pass `lambda u: u` as the
escape function, for example. One may also wish to consider
using markupsafe's escape function: markupsafe.escape().
To disable escaping entirely, one can pass `lambda u: u`
as the escape function, for example. One may also wish to
consider using markupsafe's escape function: markupsafe.escape().
This argument defaults to the package default.
file_encoding: the name of the default encoding to use when reading
template files. All templates are converted to unicode prior
......@@ -160,9 +160,16 @@ class Renderer(object):
"""
return unicode(self.escape(self._to_unicode_soft(s)))
def unicode(self, s, encoding=None):
def unicode(self, b, encoding=None):
"""
Convert a string to unicode, using string_encoding and decode_errors.
Convert a byte string to unicode, using string_encoding and decode_errors.
Arguments:
b: a byte string.
encoding: the name of an encoding. Defaults to the string_encoding
attribute for this instance.
Raises:
......@@ -178,7 +185,7 @@ class Renderer(object):
# TODO: Wrap UnicodeDecodeErrors with a message about setting
# the string_encoding and decode_errors attributes.
return unicode(s, encoding, self.decode_errors)
return unicode(b, encoding, self.decode_errors)
def _make_loader(self):
"""
......
......@@ -55,10 +55,10 @@ class AssertStringMixin:
description = details % reason
return format % description
self.assertEquals(actual, expected, make_message("different characters"))
self.assertEqual(actual, expected, make_message("different characters"))
reason = "types different: %s != %s (actual)" % (repr(type(expected)), repr(type(actual)))
self.assertEquals(type(expected), type(actual), make_message(reason))
self.assertEqual(type(expected), type(actual), make_message(reason))
class AssertIsMixin:
......
......@@ -39,7 +39,7 @@ class CommandsTestCase(unittest.TestCase):
"""
actual = self.callScript("Hi {{thing}}", '{"thing": "world"}')
self.assertEquals(actual, u"Hi world\n")
self.assertEqual(actual, u"Hi world\n")
def tearDown(self):
sys.stdout = ORIGINAL_STDOUT
......@@ -58,7 +58,7 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
"""
item = {"foo": "bar"}
self.assertEquals(_get_value(item, "foo"), "bar")
self.assertEqual(_get_value(item, "foo"), "bar")
def test_dictionary__callable_not_called(self):
"""
......@@ -87,7 +87,7 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
"""
item = {}
attr_name = "keys"
self.assertEquals(getattr(item, attr_name)(), [])
self.assertEqual(getattr(item, attr_name)(), [])
self.assertNotFound(item, attr_name)
def test_dictionary__dict_subclass(self):
......@@ -100,7 +100,7 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
item = DictSubclass()
item["foo"] = "bar"
self.assertEquals(_get_value(item, "foo"), "bar")
self.assertEqual(_get_value(item, "foo"), "bar")
### Case: the item is an object.
......@@ -110,7 +110,7 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
"""
item = SimpleObject()
self.assertEquals(_get_value(item, "foo"), "bar")
self.assertEqual(_get_value(item, "foo"), "bar")
def test_object__attribute_missing(self):
"""
......@@ -126,7 +126,7 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
"""
item = SimpleObject()
self.assertEquals(_get_value(item, "foo_callable"), "called...")
self.assertEqual(_get_value(item, "foo_callable"), "called...")
def test_object__non_built_in_type(self):
"""
......@@ -134,7 +134,7 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
"""
item = datetime(2012, 1, 2)
self.assertEquals(_get_value(item, "day"), 2)
self.assertEqual(_get_value(item, "day"), 2)
def test_object__dict_like(self):
"""
......@@ -142,7 +142,7 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
"""
item = DictLike()
self.assertEquals(item["foo"], "bar")
self.assertEqual(item["foo"], "bar")
self.assertNotFound(item, "foo")
### Case: the item is an instance of a built-in type.
......@@ -168,10 +168,10 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
#
return
self.assertEquals(item1.real, 10)
self.assertEquals(item2.real, 10)
self.assertEqual(item1.real, 10)
self.assertEqual(item2.real, 10)
self.assertEquals(_get_value(item1, 'real'), 10)
self.assertEqual(_get_value(item1, 'real'), 10)
self.assertNotFound(item2, 'real')
def test_built_in_type__string(self):
......@@ -184,10 +184,10 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
item1 = MyStr('abc')
item2 = 'abc'
self.assertEquals(item1.upper(), 'ABC')
self.assertEquals(item2.upper(), 'ABC')
self.assertEqual(item1.upper(), 'ABC')
self.assertEqual(item2.upper(), 'ABC')
self.assertEquals(_get_value(item1, 'upper'), 'ABC')
self.assertEqual(_get_value(item1, 'upper'), 'ABC')
self.assertNotFound(item2, 'upper')
def test_built_in_type__list(self):
......@@ -200,10 +200,10 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
item1 = MyList([1, 2, 3])
item2 = [1, 2, 3]
self.assertEquals(item1.pop(), 3)
self.assertEquals(item2.pop(), 3)
self.assertEqual(item1.pop(), 3)
self.assertEqual(item2.pop(), 3)
self.assertEquals(_get_value(item1, 'pop'), 2)
self.assertEqual(_get_value(item1, 'pop'), 2)
self.assertNotFound(item2, 'pop')
......@@ -230,23 +230,23 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
def test__repr(self):
context = Context()
self.assertEquals(repr(context), 'Context()')
self.assertEqual(repr(context), 'Context()')
context = Context({'foo': 'bar'})
self.assertEquals(repr(context), "Context({'foo': 'bar'},)")
self.assertEqual(repr(context), "Context({'foo': 'bar'},)")
context = Context({'foo': 'bar'}, {'abc': 123})
self.assertEquals(repr(context), "Context({'foo': 'bar'}, {'abc': 123})")
self.assertEqual(repr(context), "Context({'foo': 'bar'}, {'abc': 123})")
def test__str(self):
context = Context()
self.assertEquals(str(context), 'Context()')
self.assertEqual(str(context), 'Context()')
context = Context({'foo': 'bar'})
self.assertEquals(str(context), "Context({'foo': 'bar'},)")
self.assertEqual(str(context), "Context({'foo': 'bar'},)")
context = Context({'foo': 'bar'}, {'abc': 123})
self.assertEquals(str(context), "Context({'foo': 'bar'}, {'abc': 123})")
self.assertEqual(str(context), "Context({'foo': 'bar'}, {'abc': 123})")
## Test the static create() method.
......@@ -256,7 +256,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context.create({'foo': 'bar'})
self.assertEquals(context.get('foo'), 'bar')
self.assertEqual(context.get('foo'), 'bar')
def test_create__none(self):
"""
......@@ -264,7 +264,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context.create({'foo': 'bar'}, None)
self.assertEquals(context.get('foo'), 'bar')
self.assertEqual(context.get('foo'), 'bar')
def test_create__object(self):
"""
......@@ -274,7 +274,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
class Foo(object):
foo = 'bar'
context = Context.create(Foo())
self.assertEquals(context.get('foo'), 'bar')
self.assertEqual(context.get('foo'), 'bar')
def test_create__context(self):
"""
......@@ -283,7 +283,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
obj = Context({'foo': 'bar'})
context = Context.create(obj)
self.assertEquals(context.get('foo'), 'bar')
self.assertEqual(context.get('foo'), 'bar')
def test_create__kwarg(self):
"""
......@@ -291,7 +291,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context.create(foo='bar')
self.assertEquals(context.get('foo'), 'bar')
self.assertEqual(context.get('foo'), 'bar')
def test_create__precedence_positional(self):
"""
......@@ -299,7 +299,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context.create({'foo': 'bar'}, {'foo': 'buzz'})
self.assertEquals(context.get('foo'), 'buzz')
self.assertEqual(context.get('foo'), 'buzz')
def test_create__precedence_keyword(self):
"""
......@@ -307,7 +307,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context.create({'foo': 'bar'}, foo='buzz')
self.assertEquals(context.get('foo'), 'buzz')
self.assertEqual(context.get('foo'), 'buzz')
def test_get__key_present(self):
"""
......@@ -315,7 +315,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context({"foo": "bar"})
self.assertEquals(context.get("foo"), "bar")
self.assertEqual(context.get("foo"), "bar")
def test_get__key_missing(self):
"""
......@@ -331,7 +331,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context()
self.assertEquals(context.get("foo", "bar"), "bar")
self.assertEqual(context.get("foo", "bar"), "bar")
def test_get__precedence(self):
"""
......@@ -339,7 +339,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context({"foo": "bar"}, {"foo": "buzz"})
self.assertEquals(context.get("foo"), "buzz")
self.assertEqual(context.get("foo"), "buzz")
def test_get__fallback(self):
"""
......@@ -347,7 +347,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
context = Context({"fuzz": "buzz"}, {"foo": "bar"})
self.assertEquals(context.get("fuzz"), "buzz")
self.assertEqual(context.get("fuzz"), "buzz")
def test_push(self):
"""
......@@ -356,10 +356,10 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
key = "foo"
context = Context({key: "bar"})
self.assertEquals(context.get(key), "bar")
self.assertEqual(context.get(key), "bar")
context.push({key: "buzz"})
self.assertEquals(context.get(key), "buzz")
self.assertEqual(context.get(key), "buzz")
def test_pop(self):
"""
......@@ -368,33 +368,33 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
"""
key = "foo"
context = Context({key: "bar"}, {key: "buzz"})
self.assertEquals(context.get(key), "buzz")
self.assertEqual(context.get(key), "buzz")
item = context.pop()
self.assertEquals(item, {"foo": "buzz"})
self.assertEquals(context.get(key), "bar")
self.assertEqual(item, {"foo": "buzz"})
self.assertEqual(context.get(key), "bar")
def test_top(self):
key = "foo"
context = Context({key: "bar"}, {key: "buzz"})
self.assertEquals(context.get(key), "buzz")
self.assertEqual(context.get(key), "buzz")
top = context.top()
self.assertEquals(top, {"foo": "buzz"})
self.assertEqual(top, {"foo": "buzz"})
# Make sure calling top() didn't remove the item from the stack.
self.assertEquals(context.get(key), "buzz")
self.assertEqual(context.get(key), "buzz")
def test_copy(self):
key = "foo"
original = Context({key: "bar"}, {key: "buzz"})
self.assertEquals(original.get(key), "buzz")
self.assertEqual(original.get(key), "buzz")
new = original.copy()
# Confirm that the copy behaves the same.
self.assertEquals(new.get(key), "buzz")
self.assertEqual(new.get(key), "buzz")
# Change the copy, and confirm it is changed.
new.pop()
self.assertEquals(new.get(key), "bar")
self.assertEqual(new.get(key), "bar")
# Confirm the original is unchanged.
self.assertEquals(original.get(key), "buzz")
self.assertEqual(original.get(key), "buzz")
......@@ -95,7 +95,7 @@ Again, Welcome!""")
view.template = '''{{>partial_in_partial}}'''
actual = renderer.render(view, {'prop': 'derp'})
self.assertEquals(actual, 'Hi derp!')
self.assertEqual(actual, 'Hi derp!')
if __name__ == '__main__':
unittest.main()
......@@ -18,30 +18,30 @@ class LoaderTests(unittest.TestCase, AssertStringMixin):
def test_init__extension(self):
loader = Loader(extension='foo')
self.assertEquals(loader.extension, 'foo')
self.assertEqual(loader.extension, 'foo')
def test_init__extension__default(self):
# Test the default value.
loader = Loader()
self.assertEquals(loader.extension, 'mustache')
self.assertEqual(loader.extension, 'mustache')
def test_init__file_encoding(self):
loader = Loader(file_encoding='bar')
self.assertEquals(loader.file_encoding, 'bar')
self.assertEqual(loader.file_encoding, 'bar')
def test_init__file_encoding__default(self):
file_encoding = defaults.FILE_ENCODING
try:
defaults.FILE_ENCODING = 'foo'
loader = Loader()
self.assertEquals(loader.file_encoding, 'foo')
self.assertEqual(loader.file_encoding, 'foo')
finally:
defaults.FILE_ENCODING = file_encoding
def test_init__to_unicode(self):
to_unicode = lambda x: x
loader = Loader(to_unicode=to_unicode)
self.assertEquals(loader.to_unicode, to_unicode)
self.assertEqual(loader.to_unicode, to_unicode)
def test_init__to_unicode__default(self):
loader = Loader()
......
......@@ -26,10 +26,10 @@ class LocatorTests(unittest.TestCase):
def test_init__extension(self):
# Test the default value.
locator = Locator()
self.assertEquals(locator.template_extension, 'mustache')
self.assertEqual(locator.template_extension, 'mustache')
locator = Locator(extension='txt')
self.assertEquals(locator.template_extension, 'txt')
self.assertEqual(locator.template_extension, 'txt')
locator = Locator(extension=False)
self.assertTrue(locator.template_extension is False)
......@@ -40,40 +40,40 @@ class LocatorTests(unittest.TestCase):
obj = SayHello()
actual = locator.get_object_directory(obj)
self.assertEquals(actual, os.path.abspath(DATA_DIR))
self.assertEqual(actual, os.path.abspath(DATA_DIR))
def test_get_object_directory__not_hasattr_module(self):
locator = Locator()
obj = datetime(2000, 1, 1)
self.assertFalse(hasattr(obj, '__module__'))
self.assertEquals(locator.get_object_directory(obj), None)
self.assertEqual(locator.get_object_directory(obj), None)
self.assertFalse(hasattr(None, '__module__'))
self.assertEquals(locator.get_object_directory(None), None)
self.assertEqual(locator.get_object_directory(None), None)
def test_make_file_name(self):
locator = Locator()
locator.template_extension = 'bar'
self.assertEquals(locator.make_file_name('foo'), 'foo.bar')
self.assertEqual(locator.make_file_name('foo'), 'foo.bar')
locator.template_extension = False
self.assertEquals(locator.make_file_name('foo'), 'foo')
self.assertEqual(locator.make_file_name('foo'), 'foo')
locator.template_extension = ''
self.assertEquals(locator.make_file_name('foo'), 'foo.')
self.assertEqual(locator.make_file_name('foo'), 'foo.')
def test_make_file_name__template_extension_argument(self):
locator = Locator()
self.assertEquals(locator.make_file_name('foo', template_extension='bar'), 'foo.bar')
self.assertEqual(locator.make_file_name('foo', template_extension='bar'), 'foo.bar')
def test_find_name(self):
locator = Locator()
path = locator.find_name(search_dirs=['examples'], template_name='simple')
self.assertEquals(os.path.basename(path), 'simple.mustache')
self.assertEqual(os.path.basename(path), 'simple.mustache')
def test_find_name__using_list_of_paths(self):
locator = Locator()
......@@ -98,7 +98,7 @@ class LocatorTests(unittest.TestCase):
dirpath = os.path.dirname(path)
dirname = os.path.split(dirpath)[-1]
self.assertEquals(dirname, 'locator')
self.assertEqual(dirname, 'locator')
def test_find_name__non_existent_template_fails(self):
locator = Locator()
......@@ -113,7 +113,7 @@ class LocatorTests(unittest.TestCase):
actual = locator.find_object(search_dirs=[], obj=obj, file_name='sample_view.mustache')
expected = os.path.abspath(os.path.join(DATA_DIR, 'sample_view.mustache'))
self.assertEquals(actual, expected)
self.assertEqual(actual, expected)
def test_find_object__none_file_name(self):
locator = Locator()
......@@ -123,18 +123,18 @@ class LocatorTests(unittest.TestCase):
actual = locator.find_object(search_dirs=[], obj=obj)
expected = os.path.abspath(os.path.join(DATA_DIR, 'say_hello.mustache'))
self.assertEquals(actual, expected)
self.assertEqual(actual, expected)
def test_find_object__none_object_directory(self):
locator = Locator()
obj = None
self.assertEquals(None, locator.get_object_directory(obj))
self.assertEqual(None, locator.get_object_directory(obj))
actual = locator.find_object(search_dirs=[DATA_DIR], obj=obj, file_name='say_hello.mustache')
expected = os.path.join(DATA_DIR, 'say_hello.mustache')
self.assertEquals(actual, expected)
self.assertEqual(actual, expected)
def test_make_template_name(self):
"""
......@@ -147,4 +147,4 @@ class LocatorTests(unittest.TestCase):
pass
foo = FooBar()
self.assertEquals(locator.make_template_name(foo), 'foo_bar')
self.assertEqual(locator.make_template_name(foo), 'foo_bar')
......@@ -9,6 +9,7 @@ Creates a unittest.TestCase for the tests defined in the mustache spec.
FILE_ENCODING = 'utf-8' # the encoding of the spec test files.
yaml = None
try:
# We try yaml first since it is more convenient when adding and modifying
......@@ -31,28 +32,28 @@ else:
parser = yaml
import codecs
import glob
import os.path
import unittest
import pystache
from pystache import common
from pystache.renderer import Renderer
from pystache.tests.common import AssertStringMixin, SPEC_TEST_DIR
spec_paths = glob.glob(os.path.join(SPEC_TEST_DIR, '*.%s' % file_extension))
def parse(u, file_extension):
def parse(u):
"""
Parse
Arguments:
u: a unicode string.
"""
# TODO: find a cleaner mechanism for choosing between the two.
if file_extension[0] == 'j':
# Then json.
if yaml is None:
# Then use json.
# The only way to get the simplejson module to return unicode strings
# is to pass it unicode. See, for example--
......@@ -156,20 +157,14 @@ def buildTest(testData, spec_filename, parser):
return test
for spec_path in spec_paths:
file_name = os.path.basename(spec_path)
spec_paths = glob.glob(os.path.join(SPEC_TEST_DIR, '*.%s' % file_extension))
for path in spec_paths:
# We avoid use of the with keyword for Python 2.4 support.
# TODO: share code here with pystache's open() code.
f = open(spec_path, 'r')
try:
s = f.read()
finally:
f.close()
file_name = os.path.basename(path)
u = s.decode(FILE_ENCODING)
spec_data = parse(u, file_extension)
b = common.read(path)
u = unicode(b, encoding=FILE_ENCODING)
spec_data = parse(u)
tests = spec_data['tests']
......
......@@ -9,15 +9,15 @@ class PystacheTests(unittest.TestCase):
def _assert_rendered(self, expected, template, context):
actual = pystache.render(template, context)
self.assertEquals(actual, expected)
self.assertEqual(actual, expected)
def test_basic(self):
ret = pystache.render("Hi {{thing}}!", { 'thing': 'world' })
self.assertEquals(ret, "Hi world!")
self.assertEqual(ret, "Hi world!")
def test_kwargs(self):
ret = pystache.render("Hi {{thing}}!", thing='world')
self.assertEquals(ret, "Hi world!")
self.assertEqual(ret, "Hi world!")
def test_less_basic(self):
template = "It's a nice day for {{beverage}}, right {{person}}?"
......@@ -42,7 +42,7 @@ class PystacheTests(unittest.TestCase):
def test_comments(self):
template = "What {{! the }} what?"
actual = pystache.render(template)
self.assertEquals("What what?", actual)
self.assertEqual("What what?", actual)
def test_false_sections_are_hidden(self):
template = "Ready {{#set}}set {{/set}}go!"
......
......@@ -5,10 +5,10 @@ Unit tests of renderengine.py.
"""
import cgi
import unittest
from pystache.context import Context
from pystache import defaults
from pystache.parser import ParsingError
from pystache.renderengine import RenderEngine
from pystache.tests.common import AssertStringMixin
......@@ -26,9 +26,9 @@ class RenderEngineTestCase(unittest.TestCase):
# In real-life, these arguments would be functions
engine = RenderEngine(load_partial="foo", literal="literal", escape="escape")
self.assertEquals(engine.escape, "escape")
self.assertEquals(engine.literal, "literal")
self.assertEquals(engine.load_partial, "foo")
self.assertEqual(engine.escape, "escape")
self.assertEqual(engine.literal, "literal")
self.assertEqual(engine.load_partial, "foo")
class RenderTests(unittest.TestCase, AssertStringMixin):
......@@ -47,7 +47,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin):
Create and return a default RenderEngine for testing.
"""
escape = lambda s: unicode(cgi.escape(s))
escape = defaults.TAG_ESCAPE
engine = RenderEngine(literal=unicode, escape=escape, load_partial=None)
return engine
......@@ -230,7 +230,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin):
#
# we need to resort to built-in attributes (double-underscored) on
# the integer type.
self._assert_builtin_type(15, '__hex__', '0xf', u'999')
self._assert_builtin_type(15, '__neg__', -15, u'999')
def test_interpolation__built_in_type__list(self):
"""
......@@ -315,7 +315,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin):
try:
self._assert_render(None, template)
except ParsingError, err:
self.assertEquals(str(err), "Section end tag mismatch: u'section' != None")
self.assertEqual(str(err), "Section end tag mismatch: section != None")
def test_section__end_tag_mismatch(self):
"""
......@@ -326,7 +326,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin):
try:
self._assert_render(None, template)
except ParsingError, err:
self.assertEquals(str(err), "Section end tag mismatch: u'section_end' != u'section_start'")
self.assertEqual(str(err), "Section end tag mismatch: section_end != section_start")
def test_section__context_values(self):
"""
......
......@@ -20,6 +20,22 @@ from pystache.tests.common import AssertStringMixin
from pystache.tests.data.views import SayHello
def _make_renderer():
"""
Return a default Renderer instance for testing purposes.
"""
renderer = Renderer(string_encoding='ascii', file_encoding='ascii')
return renderer
def mock_unicode(b, encoding=None):
if encoding is None:
encoding = 'ascii'
u = unicode(b, encoding=encoding)
return u.upper()
class RendererInitTestCase(unittest.TestCase):
"""
......@@ -41,20 +57,24 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer(partials={'foo': 'bar'})
self.assertEquals(renderer.partials, {'foo': 'bar'})
self.assertEqual(renderer.partials, {'foo': 'bar'})
def test_escape__default(self):
escape = Renderer().escape
self.assertEquals(escape(">"), ">")
self.assertEquals(escape('"'), """)
# Single quotes are not escaped.
self.assertEquals(escape("'"), "'")
self.assertEqual(escape(">"), ">")
self.assertEqual(escape('"'), """)
# Single quotes are escaped in Python 3 but not Python 2.
if sys.version_info < (3, ):
expected = "'"
else:
expected = '&#x27;'
self.assertEqual(escape("'"), expected)
def test_escape(self):
escape = lambda s: "**" + s
renderer = Renderer(escape=escape)
self.assertEquals(renderer.escape("bar"), "**bar")
self.assertEqual(renderer.escape("bar"), "**bar")
def test_decode_errors__default(self):
"""
......@@ -62,7 +82,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer()
self.assertEquals(renderer.decode_errors, 'strict')
self.assertEqual(renderer.decode_errors, 'strict')
def test_decode_errors(self):
"""
......@@ -70,7 +90,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer(decode_errors="foo")
self.assertEquals(renderer.decode_errors, "foo")
self.assertEqual(renderer.decode_errors, "foo")
def test_file_encoding__default(self):
"""
......@@ -78,7 +98,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer()
self.assertEquals(renderer.file_encoding, renderer.string_encoding)
self.assertEqual(renderer.file_encoding, renderer.string_encoding)
def test_file_encoding(self):
"""
......@@ -86,7 +106,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer(file_encoding='foo')
self.assertEquals(renderer.file_encoding, 'foo')
self.assertEqual(renderer.file_encoding, 'foo')
def test_file_extension__default(self):
"""
......@@ -94,7 +114,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer()
self.assertEquals(renderer.file_extension, 'mustache')
self.assertEqual(renderer.file_extension, 'mustache')
def test_file_extension(self):
"""
......@@ -102,7 +122,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer(file_extension='foo')
self.assertEquals(renderer.file_extension, 'foo')
self.assertEqual(renderer.file_extension, 'foo')
def test_search_dirs__default(self):
"""
......@@ -110,7 +130,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer()
self.assertEquals(renderer.search_dirs, [os.curdir])
self.assertEqual(renderer.search_dirs, [os.curdir])
def test_search_dirs__string(self):
"""
......@@ -118,7 +138,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer(search_dirs='foo')
self.assertEquals(renderer.search_dirs, ['foo'])
self.assertEqual(renderer.search_dirs, ['foo'])
def test_search_dirs__list(self):
"""
......@@ -126,7 +146,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer(search_dirs=['foo'])
self.assertEquals(renderer.search_dirs, ['foo'])
self.assertEqual(renderer.search_dirs, ['foo'])
def test_string_encoding__default(self):
"""
......@@ -134,7 +154,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer()
self.assertEquals(renderer.string_encoding, sys.getdefaultencoding())
self.assertEqual(renderer.string_encoding, sys.getdefaultencoding())
def test_string_encoding(self):
"""
......@@ -142,7 +162,7 @@ class RendererInitTestCase(unittest.TestCase):
"""
renderer = Renderer(string_encoding="foo")
self.assertEquals(renderer.string_encoding, "foo")
self.assertEqual(renderer.string_encoding, "foo")
class RendererTests(unittest.TestCase, AssertStringMixin):
......@@ -166,7 +186,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
self.assertRaises(UnicodeDecodeError, renderer.unicode, s)
renderer.string_encoding = "utf-8"
self.assertEquals(renderer.unicode(s), u"é")
self.assertEqual(renderer.unicode(s), u"é")
def test_unicode__decode_errors(self):
"""
......@@ -178,11 +198,11 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
s = "déf"
renderer.decode_errors = "ignore"
self.assertEquals(renderer.unicode(s), "df")
self.assertEqual(renderer.unicode(s), "df")
renderer.decode_errors = "replace"
# U+FFFD is the official Unicode replacement character.
self.assertEquals(renderer.unicode(s), u'd\ufffd\ufffdf')
self.assertEqual(renderer.unicode(s), u'd\ufffd\ufffdf')
## Test the _make_loader() method.
......@@ -194,7 +214,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
renderer = Renderer()
loader = renderer._make_loader()
self.assertEquals(type(loader), Loader)
self.assertEqual(type(loader), Loader)
def test__make_loader__attributes(self):
"""
......@@ -210,9 +230,9 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
loader = renderer._make_loader()
self.assertEquals(loader.extension, 'ext')
self.assertEquals(loader.file_encoding, 'enc')
self.assertEquals(loader.to_unicode, unicode_)
self.assertEqual(loader.extension, 'ext')
self.assertEqual(loader.file_encoding, 'enc')
self.assertEqual(loader.to_unicode, unicode_)
## Test the render() method.
......@@ -223,22 +243,22 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
"""
renderer = Renderer()
rendered = renderer.render('foo')
self.assertEquals(type(rendered), unicode)
self.assertEqual(type(rendered), unicode)
def test_render__unicode(self):
renderer = Renderer()
actual = renderer.render(u'foo')
self.assertEquals(actual, u'foo')
self.assertEqual(actual, u'foo')
def test_render__str(self):
renderer = Renderer()
actual = renderer.render('foo')
self.assertEquals(actual, 'foo')
self.assertEqual(actual, 'foo')
def test_render__non_ascii_character(self):
renderer = Renderer()
actual = renderer.render(u'Poincaré')
self.assertEquals(actual, u'Poincaré')
self.assertEqual(actual, u'Poincaré')
def test_render__context(self):
"""
......@@ -246,7 +266,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
"""
renderer = Renderer()
self.assertEquals(renderer.render('Hi {{person}}', {'person': 'Mom'}), 'Hi Mom')
self.assertEqual(renderer.render('Hi {{person}}', {'person': 'Mom'}), 'Hi Mom')
def test_render__context_and_kwargs(self):
"""
......@@ -255,7 +275,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
"""
renderer = Renderer()
template = 'Hi {{person1}} and {{person2}}'
self.assertEquals(renderer.render(template, {'person1': 'Mom'}, person2='Dad'), 'Hi Mom and Dad')
self.assertEqual(renderer.render(template, {'person1': 'Mom'}, person2='Dad'), 'Hi Mom and Dad')
def test_render__kwargs_and_no_context(self):
"""
......@@ -263,7 +283,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
"""
renderer = Renderer()
self.assertEquals(renderer.render('Hi {{person}}', person='Mom'), 'Hi Mom')
self.assertEqual(renderer.render('Hi {{person}}', person='Mom'), 'Hi Mom')
def test_render__context_and_kwargs__precedence(self):
"""
......@@ -271,7 +291,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
"""
renderer = Renderer()
self.assertEquals(renderer.render('Hi {{person}}', {'person': 'Mom'}, person='Dad'), 'Hi Dad')
self.assertEqual(renderer.render('Hi {{person}}', {'person': 'Mom'}, person='Dad'), 'Hi Dad')
def test_render__kwargs_does_not_modify_context(self):
"""
......@@ -281,23 +301,23 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
context = {}
renderer = Renderer()
renderer.render('Hi {{person}}', context=context, foo="bar")
self.assertEquals(context, {})
self.assertEqual(context, {})
def test_render__nonascii_template(self):
"""
Test passing a non-unicode template with non-ascii characters.
"""
renderer = Renderer()
template = "déf"
renderer = _make_renderer()
template = u"déf".encode("utf-8")
# Check that decode_errors and string_encoding are both respected.
renderer.decode_errors = 'ignore'
renderer.string_encoding = 'ascii'
self.assertEquals(renderer.render(template), "df")
self.assertEqual(renderer.render(template), "df")
renderer.string_encoding = 'utf_8'
self.assertEquals(renderer.render(template), u"déf")
self.assertEqual(renderer.render(template), u"déf")
def test_make_load_partial(self):
"""
......@@ -309,8 +329,8 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
load_partial = renderer._make_load_partial()
actual = load_partial('foo')
self.assertEquals(actual, 'bar')
self.assertEquals(type(actual), unicode, "RenderEngine requires that "
self.assertEqual(actual, 'bar')
self.assertEqual(type(actual), unicode, "RenderEngine requires that "
"load_partial return unicode strings.")
def test_make_load_partial__unicode(self):
......@@ -322,14 +342,14 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
renderer.partials = {'partial': 'foo'}
load_partial = renderer._make_load_partial()
self.assertEquals(load_partial("partial"), "foo")
self.assertEqual(load_partial("partial"), "foo")
# Now with a value that is already unicode.
renderer.partials = {'partial': u'foo'}
load_partial = renderer._make_load_partial()
# If the next line failed, we would get the following error:
# TypeError: decoding Unicode is not supported
self.assertEquals(load_partial("partial"), "foo")
self.assertEqual(load_partial("partial"), "foo")
def test_render_path(self):
"""
......@@ -339,7 +359,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
renderer = Renderer()
path = get_data_path('say_hello.mustache')
actual = renderer.render_path(path, to='foo')
self.assertEquals(actual, "Hello, foo")
self.assertEqual(actual, "Hello, foo")
def test_render__object(self):
"""
......@@ -350,10 +370,10 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
say_hello = SayHello()
actual = renderer.render(say_hello)
self.assertEquals('Hello, World', actual)
self.assertEqual('Hello, World', actual)
actual = renderer.render(say_hello, to='Mars')
self.assertEquals('Hello, Mars', actual)
self.assertEqual('Hello, Mars', actual)
def test_render__template_spec(self):
"""
......@@ -379,7 +399,7 @@ class RendererTests(unittest.TestCase, AssertStringMixin):
view = Simple()
actual = renderer.render(view)
self.assertEquals('Hi pizza!', actual)
self.assertEqual('Hi pizza!', actual)
# By testing that Renderer.render() constructs the right RenderEngine,
......@@ -393,6 +413,13 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
"""
def _make_renderer(self):
"""
Return a default Renderer instance for testing purposes.
"""
return _make_renderer()
## Test the engine's load_partial attribute.
def test__load_partial__returns_unicode(self):
......@@ -410,13 +437,13 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
engine = renderer._make_render_engine()
actual = engine.load_partial('str')
self.assertEquals(actual, "foo")
self.assertEquals(type(actual), unicode)
self.assertEqual(actual, "foo")
self.assertEqual(type(actual), unicode)
# Check that unicode subclasses are not preserved.
actual = engine.load_partial('subclass')
self.assertEquals(actual, "abc")
self.assertEquals(type(actual), unicode)
self.assertEqual(actual, "abc")
self.assertEqual(type(actual), unicode)
def test__load_partial__not_found(self):
"""
......@@ -433,7 +460,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
load_partial("foo")
raise Exception("Shouldn't get here")
except Exception, err:
self.assertEquals(str(err), "Partial not found with name: 'foo'")
self.assertEqual(str(err), "Partial not found with name: 'foo'")
## Test the engine's literal attribute.
......@@ -442,13 +469,14 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
Test that literal uses the renderer's unicode function.
"""
renderer = Renderer()
renderer.unicode = lambda s: s.upper()
renderer = self._make_renderer()
renderer.unicode = mock_unicode
engine = renderer._make_render_engine()
literal = engine.literal
self.assertEquals(literal("foo"), "FOO")
b = u"foo".encode("ascii")
self.assertEqual(literal(b), "FOO")
def test__literal__handles_unicode(self):
"""
......@@ -461,7 +489,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
engine = renderer._make_render_engine()
literal = engine.literal
self.assertEquals(literal(u"foo"), "foo")
self.assertEqual(literal(u"foo"), "foo")
def test__literal__returns_unicode(self):
"""
......@@ -474,16 +502,16 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
engine = renderer._make_render_engine()
literal = engine.literal
self.assertEquals(type(literal("foo")), unicode)
self.assertEqual(type(literal("foo")), unicode)
class MyUnicode(unicode):
pass
s = MyUnicode("abc")
self.assertEquals(type(s), MyUnicode)
self.assertEqual(type(s), MyUnicode)
self.assertTrue(isinstance(s, unicode))
self.assertEquals(type(literal(s)), unicode)
self.assertEqual(type(literal(s)), unicode)
## Test the engine's escape attribute.
......@@ -498,7 +526,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
engine = renderer._make_render_engine()
escape = engine.escape
self.assertEquals(escape("foo"), "**foo")
self.assertEqual(escape("foo"), "**foo")
def test__escape__uses_renderer_unicode(self):
"""
......@@ -506,12 +534,13 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
"""
renderer = Renderer()
renderer.unicode = lambda s: s.upper()
renderer.unicode = mock_unicode
engine = renderer._make_render_engine()
escape = engine.escape
self.assertEquals(escape("foo"), "FOO")
b = u"foo".encode('ascii')
self.assertEqual(escape(b), "FOO")
def test__escape__has_access_to_original_unicode_subclass(self):
"""
......@@ -519,7 +548,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
"""
renderer = Renderer()
renderer.escape = lambda s: type(s).__name__
renderer.escape = lambda s: unicode(type(s).__name__)
engine = renderer._make_render_engine()
escape = engine.escape
......@@ -527,9 +556,9 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
class MyUnicode(unicode):
pass
self.assertEquals(escape("foo"), "unicode")
self.assertEquals(escape(u"foo"), "unicode")
self.assertEquals(escape(MyUnicode("foo")), "MyUnicode")
self.assertEqual(escape(u"foo".encode('ascii')), unicode.__name__)
self.assertEqual(escape(u"foo"), unicode.__name__)
self.assertEqual(escape(MyUnicode("foo")), MyUnicode.__name__)
def test__escape__returns_unicode(self):
"""
......@@ -542,7 +571,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
engine = renderer._make_render_engine()
escape = engine.escape
self.assertEquals(type(escape("foo")), unicode)
self.assertEqual(type(escape("foo")), unicode)
# Check that literal doesn't preserve unicode subclasses.
class MyUnicode(unicode):
......@@ -550,7 +579,7 @@ class Renderer_MakeRenderEngineTests(unittest.TestCase):
s = MyUnicode("abc")
self.assertEquals(type(s), MyUnicode)
self.assertEqual(type(s), MyUnicode)
self.assertTrue(isinstance(s, unicode))
self.assertEquals(type(escape(s)), unicode)
self.assertEqual(type(escape(s)), unicode)
......@@ -28,11 +28,11 @@ class TestSimple(unittest.TestCase, AssertStringMixin):
renderer = Renderer()
actual = renderer.render(template, context)
self.assertEquals(actual, "Colors: red Colors: green Colors: blue ")
self.assertEqual(actual, "Colors: red Colors: green Colors: blue ")
def test_empty_context(self):
template = '{{#empty_list}}Shouldnt see me {{/empty_list}}{{^empty_list}}Should see me{{/empty_list}}'
self.assertEquals(pystache.Renderer().render(template), "Should see me")
self.assertEqual(pystache.Renderer().render(template), "Should see me")
def test_callables(self):
view = Lambdas()
......@@ -58,7 +58,7 @@ class TestSimple(unittest.TestCase, AssertStringMixin):
def test_non_existent_value_renders_blank(self):
view = Simple()
template = '{{not_set}} {{blank}}'
self.assertEquals(pystache.Renderer().render(template), ' ')
self.assertEqual(pystache.Renderer().render(template), ' ')
def test_template_partial_extension(self):
......
......@@ -18,7 +18,7 @@ from pystache import Renderer
from pystache import TemplateSpec
from pystache.locator import Locator
from pystache.loader import Loader
from pystache.spec_loader import SpecLoader
from pystache.specloader import SpecLoader
from pystache.tests.common import DATA_DIR
from pystache.tests.common import EXAMPLES_DIR
from pystache.tests.common import AssertIsMixin
......@@ -49,7 +49,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
# TODO: change this test to remove the following brittle line.
view.template_rel_directory = "../../examples"
actual = renderer.render(view)
self.assertEquals(actual, "No tags...")
self.assertEqual(actual, "No tags...")
def test_template_path_for_partials(self):
"""
......@@ -65,7 +65,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
self.assertRaises(IOError, renderer1.render, spec)
actual = renderer2.render(spec)
self.assertEquals(actual, "Partial: No tags...")
self.assertEqual(actual, "Partial: No tags...")
def test_basic_method_calls(self):
renderer = Renderer()
......@@ -79,7 +79,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
renderer = Renderer()
actual = renderer.render(view)
self.assertEquals(actual, "Hi Chris!")
self.assertEqual(actual, "Hi Chris!")
def test_complex(self):
renderer = Renderer()
......@@ -95,7 +95,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
def test_higher_order_replace(self):
renderer = Renderer()
actual = renderer.render(Lambdas())
self.assertEquals(actual, 'bar != bar. oh, it does!')
self.assertEqual(actual, 'bar != bar. oh, it does!')
def test_higher_order_rot13(self):
view = Lambdas()
......@@ -119,7 +119,7 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
renderer = Renderer(search_dirs=EXAMPLES_DIR)
actual = renderer.render(view)
self.assertEquals(actual, u'nopqrstuvwxyz')
self.assertEqual(actual, u'nopqrstuvwxyz')
def test_hierarchical_partials_with_lambdas(self):
view = Lambdas()
......@@ -152,6 +152,28 @@ class ViewTestCase(unittest.TestCase, AssertStringMixin):
self.assertString(actual, u"""one, two, three, empty list""")
def _make_specloader():
"""
Return a default SpecLoader instance for testing purposes.
"""
# Python 2 and 3 have different default encodings. Thus, to have
# consistent test results across both versions, we need to specify
# the string and file encodings explicitly rather than relying on
# the defaults.
def to_unicode(s, encoding=None):
"""
Raises a TypeError exception if the given string is already unicode.
"""
if encoding is None:
encoding = 'ascii'
return unicode(s, encoding, 'strict')
loader = Loader(file_encoding='ascii', to_unicode=to_unicode)
return SpecLoader(loader=loader)
class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
"""
......@@ -159,13 +181,16 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
"""
def _make_specloader(self):
return _make_specloader()
def test_init__defaults(self):
custom = SpecLoader()
spec_loader = SpecLoader()
# Check the loader attribute.
loader = custom.loader
self.assertEquals(loader.extension, 'mustache')
self.assertEquals(loader.file_encoding, sys.getdefaultencoding())
loader = spec_loader.loader
self.assertEqual(loader.extension, 'mustache')
self.assertEqual(loader.file_encoding, sys.getdefaultencoding())
# TODO: finish testing the other Loader attributes.
to_unicode = loader.to_unicode
......@@ -187,7 +212,8 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
custom = TemplateSpec()
custom.template = "abc"
self._assert_template(SpecLoader(), custom, u"abc")
spec_loader = self._make_specloader()
self._assert_template(spec_loader, custom, u"abc")
def test_load__template__type_unicode(self):
"""
......@@ -197,7 +223,8 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
custom = TemplateSpec()
custom.template = u"abc"
self._assert_template(SpecLoader(), custom, u"abc")
spec_loader = self._make_specloader()
self._assert_template(spec_loader, custom, u"abc")
def test_load__template__unicode_non_ascii(self):
"""
......@@ -207,7 +234,8 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
custom = TemplateSpec()
custom.template = u"é"
self._assert_template(SpecLoader(), custom, u"é")
spec_loader = self._make_specloader()
self._assert_template(spec_loader, custom, u"é")
def test_load__template__with_template_encoding(self):
"""
......@@ -217,10 +245,12 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
custom = TemplateSpec()
custom.template = u'é'.encode('utf-8')
self.assertRaises(UnicodeDecodeError, self._assert_template, SpecLoader(), custom, u'é')
spec_loader = self._make_specloader()
self.assertRaises(UnicodeDecodeError, self._assert_template, spec_loader, custom, u'é')
custom.template_encoding = 'utf-8'
self._assert_template(SpecLoader(), custom, u'é')
self._assert_template(spec_loader, custom, u'é')
# TODO: make this test complete.
def test_load__template__correct_loader(self):
......@@ -255,8 +285,8 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
# Check that our unicode() above was called.
self._assert_template(custom_loader, view, u'foo')
self.assertEquals(loader.s, "template-foo")
self.assertEquals(loader.encoding, "encoding-foo")
self.assertEqual(loader.s, "template-foo")
self.assertEqual(loader.encoding, "encoding-foo")
# TODO: migrate these tests into the SpecLoaderTests class.
......@@ -266,14 +296,13 @@ class SpecLoaderTests(unittest.TestCase, AssertIsMixin, AssertStringMixin):
# TemplateSpec attributes or something).
class TemplateSpecTests(unittest.TestCase):
# TODO: rename this method to _make_loader().
def _make_locator(self):
return SpecLoader()
def _make_loader(self):
return _make_specloader()
def _assert_template_location(self, view, expected):
locator = self._make_locator()
actual = locator._find_relative(view)
self.assertEquals(actual, expected)
loader = self._make_loader()
actual = loader._find_relative(view)
self.assertEqual(actual, expected)
def test_find_relative(self):
"""
......@@ -334,38 +363,38 @@ class TemplateSpecTests(unittest.TestCase):
Test _find() with a view that has a directory specified.
"""
locator = self._make_locator()
loader = self._make_loader()
view = SampleView()
view.template_rel_path = 'foo/bar.txt'
self.assertTrue(locator._find_relative(view)[0] is not None)
self.assertTrue(loader._find_relative(view)[0] is not None)
actual = locator._find(view)
actual = loader._find(view)
expected = os.path.abspath(os.path.join(DATA_DIR, 'foo/bar.txt'))
self.assertEquals(actual, expected)
self.assertEqual(actual, expected)
def test_find__without_directory(self):
"""
Test _find() with a view that doesn't have a directory specified.
"""
locator = self._make_locator()
loader = self._make_loader()
view = SampleView()
self.assertTrue(locator._find_relative(view)[0] is None)
self.assertTrue(loader._find_relative(view)[0] is None)
actual = locator._find(view)
actual = loader._find(view)
expected = os.path.abspath(os.path.join(DATA_DIR, 'sample_view.mustache'))
self.assertEquals(actual, expected)
self.assertEqual(actual, expected)
def _assert_get_template(self, custom, expected):
locator = self._make_locator()
actual = locator.load(custom)
loader = self._make_loader()
actual = loader.load(custom)
self.assertEquals(type(actual), unicode)
self.assertEquals(actual, expected)
self.assertEqual(type(actual), unicode)
self.assertEqual(actual, expected)
def test_get_template(self):
"""
......
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