summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Jerdonek <chris.jerdonek@gmail.com>2012-04-02 23:00:36 -0700
committerChris Jerdonek <chris.jerdonek@gmail.com>2012-04-02 23:00:36 -0700
commit2330183453047bc48a70fdae038fe3570f5796d3 (patch)
tree63ed4c42e999b08be45dfe3b70786bfa2d412ae7
parent135540b4f7e07d0fcf92a1e4848a63c2d582d2de (diff)
parent09906e25d2df663db3e1d80fc676768e17630f96 (diff)
downloadpystache-2330183453047bc48a70fdae038fe3570f5796d3.tar.gz
Merge branch 'development-python24' into development: code now works with Python 2.4.
All tests pass with Python 2.4 (with simplejson-2.0.9).
-rw-r--r--pystache/commands.py9
-rw-r--r--pystache/init.py4
-rw-r--r--pystache/loader.py12
-rw-r--r--pystache/locator.py2
-rw-r--r--pystache/parsed.py6
-rw-r--r--pystache/renderer.py19
-rw-r--r--pystache/spec_loader.py11
-rw-r--r--tests/test_context.py13
-rw-r--r--tests/test_examples.py4
-rw-r--r--tests/test_loader.py2
-rw-r--r--tests/test_locator.py2
-rw-r--r--tests/test_renderer.py6
-rw-r--r--tests/test_simple.py4
-rw-r--r--tests/test_spec.py60
-rw-r--r--tests/test_template_spec.py12
15 files changed, 107 insertions, 59 deletions
diff --git a/pystache/commands.py b/pystache/commands.py
index d6fb549..1801d40 100644
--- a/pystache/commands.py
+++ b/pystache/commands.py
@@ -7,7 +7,14 @@ Run this script using the -h option for command-line help.
"""
-import json
+
+try:
+ import json
+except:
+ # The json module is new in Python 2.6, whereas simplejson is
+ # compatible with earlier versions.
+ import simplejson as json
+
# The optparse module is deprecated in Python 2.7 in favor of argparse.
# However, argparse is not available in Python 2.6 and earlier.
from optparse import OptionParser
diff --git a/pystache/init.py b/pystache/init.py
index f227f78..b285a5c 100644
--- a/pystache/init.py
+++ b/pystache/init.py
@@ -5,8 +5,8 @@ This module contains the initialization logic called by __init__.py.
"""
-from .renderer import Renderer
-from .template_spec import TemplateSpec
+from pystache.renderer import Renderer
+from pystache.template_spec import TemplateSpec
__all__ = ['render', 'Renderer', 'TemplateSpec']
diff --git a/pystache/loader.py b/pystache/loader.py
index cc15d23..bcba71b 100644
--- a/pystache/loader.py
+++ b/pystache/loader.py
@@ -5,13 +5,11 @@ This module provides a Loader class for locating and reading templates.
"""
-from __future__ import with_statement
-
import os
import sys
-from . import defaults
-from .locator import Locator
+from pystache import defaults
+from pystache.locator import Locator
def _to_unicode(s, encoding=None):
@@ -108,8 +106,12 @@ class Loader(object):
Read the template at the given path, and return it as a unicode string.
"""
- with open(path, 'r') as f:
+ # We avoid use of the with keyword for Python 2.4 support.
+ f = open(path, 'r')
+ try:
text = f.read()
+ finally:
+ f.close()
if encoding is None:
encoding = self.file_encoding
diff --git a/pystache/locator.py b/pystache/locator.py
index e288049..a1f06db 100644
--- a/pystache/locator.py
+++ b/pystache/locator.py
@@ -9,7 +9,7 @@ import os
import re
import sys
-from . import defaults
+from pystache import defaults
class Locator(object):
diff --git a/pystache/parsed.py b/pystache/parsed.py
index 12b5cb0..5418ec1 100644
--- a/pystache/parsed.py
+++ b/pystache/parsed.py
@@ -37,7 +37,11 @@ class ParsedTemplate(object):
Returns: a string of type unicode.
"""
- get_unicode = lambda val: val(context) if callable(val) else val
+ # We avoid use of the ternary operator for Python 2.4 support.
+ def get_unicode(val):
+ if callable(val):
+ return val(context)
+ return val
parts = map(get_unicode, self._parse_tree)
s = ''.join(parts)
diff --git a/pystache/renderer.py b/pystache/renderer.py
index 9a0a1b3..5bd2a3f 100644
--- a/pystache/renderer.py
+++ b/pystache/renderer.py
@@ -5,12 +5,12 @@ This module provides a Renderer class to render templates.
"""
-from . import defaults
-from .context import Context
-from .loader import Loader
-from .renderengine import RenderEngine
-from .spec_loader import SpecLoader
-from .template_spec import TemplateSpec
+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.template_spec import TemplateSpec
class Renderer(object):
@@ -138,8 +138,11 @@ class Renderer(object):
Convert a basestring to unicode, preserving any unicode subclass.
"""
- # Avoid the "double-decoding" TypeError.
- return s if isinstance(s, unicode) else self.unicode(s)
+ # We type-check to avoid "TypeError: decoding Unicode is not supported".
+ # We avoid the Python ternary operator for Python 2.4 support.
+ if isinstance(s, unicode):
+ return s
+ return self.unicode(s)
def _to_unicode_hard(self, s):
"""
diff --git a/pystache/spec_loader.py b/pystache/spec_loader.py
index e18140b..3cb0f1a 100644
--- a/pystache/spec_loader.py
+++ b/pystache/spec_loader.py
@@ -7,7 +7,7 @@ This module supports customized (aka special or specified) template loading.
import os.path
-from .loader import Loader
+from pystache.loader import Loader
# TODO: add test cases for this class.
@@ -36,12 +36,15 @@ class SpecLoader(object):
"""
if spec.template_rel_path is not None:
return os.path.split(spec.template_rel_path)
-
# Otherwise, determine the file name separately.
+
locator = self.loader._make_locator()
- template_name = (spec.template_name if spec.template_name is not None else
- locator.make_template_name(spec))
+ # We do not use the ternary operator for Python 2.4 support.
+ if spec.template_name is not None:
+ template_name = spec.template_name
+ else:
+ template_name = locator.make_template_name(spec)
file_name = locator.make_file_name(template_name, spec.template_extension)
diff --git a/tests/test_context.py b/tests/test_context.py
index 49ebbd2..decf4fb 100644
--- a/tests/test_context.py
+++ b/tests/test_context.py
@@ -157,6 +157,17 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
item1 = MyInt(10)
item2 = 10
+ try:
+ item2.real
+ except AttributeError:
+ # Then skip this unit test. The numeric type hierarchy was
+ # added only in Python 2.6, in which case integers inherit
+ # from complex numbers the "real" attribute, etc:
+ #
+ # http://docs.python.org/library/numbers.html
+ #
+ return
+
self.assertEquals(item1.real, 10)
self.assertEquals(item2.real, 10)
@@ -316,7 +327,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
def test_get__default(self):
"""
- Test that get() respects the default value .
+ Test that get() respects the default value.
"""
context = Context()
diff --git a/tests/test_examples.py b/tests/test_examples.py
index 552fffd..179b089 100644
--- a/tests/test_examples.py
+++ b/tests/test_examples.py
@@ -12,8 +12,8 @@ from examples.unicode_output import UnicodeOutput
from examples.unicode_input import UnicodeInput
from examples.nested_context import NestedContext
from pystache import Renderer
-from .common import EXAMPLES_DIR
-from .common import AssertStringMixin
+from tests.common import EXAMPLES_DIR
+from tests.common import AssertStringMixin
class TestView(unittest.TestCase, AssertStringMixin):
diff --git a/tests/test_loader.py b/tests/test_loader.py
index a285e68..119ebef 100644
--- a/tests/test_loader.py
+++ b/tests/test_loader.py
@@ -9,7 +9,7 @@ import os
import sys
import unittest
-from .common import AssertStringMixin
+from tests.common import AssertStringMixin
from pystache import defaults
from pystache.loader import Loader
diff --git a/tests/test_locator.py b/tests/test_locator.py
index fc33a2f..94a55ad 100644
--- a/tests/test_locator.py
+++ b/tests/test_locator.py
@@ -14,7 +14,7 @@ import unittest
from pystache.loader import Loader as Reader
from pystache.locator import Locator
-from .common import DATA_DIR
+from tests.common import DATA_DIR
from data.views import SayHello
diff --git a/tests/test_renderer.py b/tests/test_renderer.py
index 6737cb1..a69d11a 100644
--- a/tests/test_renderer.py
+++ b/tests/test_renderer.py
@@ -15,9 +15,9 @@ from pystache import Renderer
from pystache import TemplateSpec
from pystache.loader import Loader
-from .common import get_data_path
-from .common import AssertStringMixin
-from .data.views import SayHello
+from tests.common import get_data_path
+from tests.common import AssertStringMixin
+from tests.data.views import SayHello
class RendererInitTestCase(unittest.TestCase):
diff --git a/tests/test_simple.py b/tests/test_simple.py
index 0a8a83c..e19187f 100644
--- a/tests/test_simple.py
+++ b/tests/test_simple.py
@@ -8,8 +8,8 @@ from examples.lambdas import Lambdas
from examples.template_partial import TemplatePartial
from examples.simple import Simple
-from .common import EXAMPLES_DIR
-from .common import AssertStringMixin
+from tests.common import EXAMPLES_DIR
+from tests.common import AssertStringMixin
class TestSimple(unittest.TestCase, AssertStringMixin):
diff --git a/tests/test_spec.py b/tests/test_spec.py
index a379f24..02f6080 100644
--- a/tests/test_spec.py
+++ b/tests/test_spec.py
@@ -3,32 +3,28 @@
"""
Creates a unittest.TestCase for the tests defined in the mustache spec.
-We did not call this file something like "test_spec.py" to avoid matching
-nosetests's default regular expression "(?:^|[\b_\./-])[Tt]est".
-This allows us to exclude the spec test cases by default when running
-nosetests. To include the spec tests, one can use the following option,
-for example--
+"""
- nosetests -i spec
+# TODO: this module can be cleaned up somewhat.
-"""
+try:
+ # We deserialize the json form rather than the yaml form because
+ # json libraries are available for Python 2.4.
+ import json
+except:
+ # The json module is new in Python 2.6, whereas simplejson is
+ # compatible with earlier versions.
+ import simplejson as json
import glob
import os.path
import unittest
-import yaml
from pystache.renderer import Renderer
-def code_constructor(loader, node):
- value = loader.construct_mapping(node)
- return eval(value['python'], {})
-
-yaml.add_constructor(u'!code', code_constructor)
-
-specs = os.path.join(os.path.dirname(__file__), '..', 'ext', 'spec', 'specs')
-specs = glob.glob(os.path.join(specs, '*.yml'))
+root_path = os.path.join(os.path.dirname(__file__), '..', 'ext', 'spec', 'specs')
+spec_paths = glob.glob(os.path.join(root_path, '*.json'))
class MustacheSpec(unittest.TestCase):
pass
@@ -46,8 +42,16 @@ def buildTest(testData, spec_filename):
expected = testData['expected']
data = testData['data']
+ # Convert code strings to functions.
+ # TODO: make this section of code easier to understand.
+ new_data = {}
+ for key, val in data.iteritems():
+ if isinstance(val, dict) and val.get('__tag__') == 'code':
+ val = eval(val['python'])
+ new_data[key] = val
+
renderer = Renderer(partials=partials)
- actual = renderer.render(template, data)
+ actual = renderer.render(template, new_data)
actual = actual.encode('utf-8')
message = """%s
@@ -64,14 +68,28 @@ def buildTest(testData, spec_filename):
self.assertEquals(actual, expected, message)
# The name must begin with "test" for nosetests test discovery to work.
- test.__name__ = 'test: "%s"' % test_name
+ name = 'test: "%s"' % test_name
+
+ # If we don't convert unicode to str, we get the following error:
+ # "TypeError: __name__ must be set to a string object"
+ test.__name__ = str(name)
return test
-for spec in specs:
- file_name = os.path.basename(spec)
+for spec_path in spec_paths:
+
+ file_name = os.path.basename(spec_path)
+
+ # We avoid use of the with keyword for Python 2.4 support.
+ f = open(spec_path, 'r')
+ try:
+ spec_data = json.load(f)
+ finally:
+ f.close()
+
+ tests = spec_data['tests']
- for test in yaml.load(open(spec))['tests']:
+ for test in tests:
test = buildTest(test, file_name)
setattr(MustacheSpec, test.__name__, test)
# Prevent this variable from being interpreted as another test.
diff --git a/tests/test_template_spec.py b/tests/test_template_spec.py
index 7d97af0..9599c37 100644
--- a/tests/test_template_spec.py
+++ b/tests/test_template_spec.py
@@ -19,12 +19,12 @@ from pystache import TemplateSpec
from pystache.locator import Locator
from pystache.loader import Loader
from pystache.spec_loader import SpecLoader
-from .common import DATA_DIR
-from .common import EXAMPLES_DIR
-from .common import AssertIsMixin
-from .common import AssertStringMixin
-from .data.views import SampleView
-from .data.views import NonAscii
+from tests.common import DATA_DIR
+from tests.common import EXAMPLES_DIR
+from tests.common import AssertIsMixin
+from tests.common import AssertStringMixin
+from tests.data.views import SampleView
+from tests.data.views import NonAscii
class Thing(object):