From 5adbcd9e1461b299fa26ef76efb92ceb85e06ba4 Mon Sep 17 00:00:00 2001 From: Daniel Morrison Date: Sun, 21 Sep 2014 22:41:39 -0400 Subject: [PATCH 1/2] Run 2to3 -x unicode -x basestring $ 2to3 -x unicode -x basestring --write --nobackups --no-diffs --doctests_only pystache $ 2to3 -x unicode -x basestring --write --nobackups --no-diffs pystache --- pystache/commands/render.py | 4 ++-- pystache/context.py | 3 ++- pystache/parsed.py | 2 +- pystache/parser.py | 6 ++++-- pystache/renderengine.py | 3 ++- pystache/renderer.py | 3 ++- pystache/tests/benchmark.py | 8 ++++---- pystache/tests/common.py | 10 +++++----- pystache/tests/main.py | 2 +- pystache/tests/spectesting.py | 8 ++++---- pystache/tests/test___init__.py | 4 ++-- pystache/tests/test_defaults.py | 2 +- pystache/tests/test_examples.py | 18 +++++++++--------- pystache/tests/test_renderengine.py | 13 +++++++------ pystache/tests/test_renderer.py | 2 +- pystache/tests/test_simple.py | 10 +++++----- pystache/tests/test_specloader.py | 10 +++++----- 17 files changed, 57 insertions(+), 51 deletions(-) diff --git a/pystache/commands/render.py b/pystache/commands/render.py index 1a9c309d..9c913e71 100644 --- a/pystache/commands/render.py +++ b/pystache/commands/render.py @@ -22,7 +22,7 @@ from sys import exc_info ex_type, ex_value, tb = exc_info() new_ex = Exception("%s: %s" % (ex_type.__name__, ex_value)) - raise new_ex.__class__, new_ex, tb + raise new_ex.__class__(new_ex).with_traceback(tb) # The optparse module is deprecated in Python 2.7 in favor of argparse. # However, argparse is not available in Python 2.6 and earlier. @@ -88,7 +88,7 @@ def main(sys_argv=sys.argv): context = json.loads(context) rendered = renderer.render(template, context) - print rendered + print(rendered) if __name__=='__main__': diff --git a/pystache/context.py b/pystache/context.py index 67159160..7ef9ceb9 100644 --- a/pystache/context.py +++ b/pystache/context.py @@ -15,6 +15,7 @@ """ from pystache.common import PystacheError +import collections # This equals '__builtin__' in Python 2 and 'builtins' in Python 3. @@ -69,7 +70,7 @@ def _get_value(context, key): else: # TODO: consider using EAFP here instead. # http://docs.python.org/glossary.html#term-eafp - if callable(attr): + if isinstance(attr, collections.Callable): return attr() return attr diff --git a/pystache/parsed.py b/pystache/parsed.py index 372d96c6..f017dd44 100644 --- a/pystache/parsed.py +++ b/pystache/parsed.py @@ -44,7 +44,7 @@ def get_unicode(node): if type(node) is unicode: return node return node.render(engine, context) - parts = map(get_unicode, self._parse_tree) + parts = list(map(get_unicode, self._parse_tree)) s = ''.join(parts) return unicode(s) diff --git a/pystache/parser.py b/pystache/parser.py index c6a171f0..a7a79da9 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -9,6 +9,7 @@ from pystache import defaults from pystache.parsed import ParsedTemplate +import collections END_OF_LINE_CHARACTERS = [u'\r', u'\n'] @@ -31,7 +32,7 @@ def parse(template, delimiters=None): Examples: >>> parsed = parse(u"Hey {{#who}}{{name}}!{{/who}}") - >>> print str(parsed).replace('u', '') # This is a hack to get the test to pass both in Python 2 and 3. + >>> print(str(parsed).replace('u', '')) # This is a hack to get the test to pass both in Python 2 and 3. ['Hey ', _SectionNode(key='who', index_begin=12, index_end=21, parsed=[_EscapeNode(key='name'), '!'])] """ @@ -193,7 +194,7 @@ def render(self, engine, context): parts = [] for val in values: - if callable(val): + if isinstance(val, collections.Callable): # Lambdas special case section rendering and bypass pushing # the data value onto the context stack. From the spec-- # @@ -376,3 +377,4 @@ def _make_section_node(self, template, tag_type, tag_key, parsed_section, return _InvertedNode(tag_key, parsed_section) raise Exception("Invalid symbol for section tag: %s" % repr(tag_type)) + diff --git a/pystache/renderengine.py b/pystache/renderengine.py index c797b176..564ed743 100644 --- a/pystache/renderengine.py +++ b/pystache/renderengine.py @@ -9,6 +9,7 @@ from pystache.common import is_string from pystache.parser import parse +import collections def context_get(stack, name): @@ -104,7 +105,7 @@ def fetch_string(self, context, name): """ val = self.resolve_context(context, name) - if callable(val): + if isinstance(val, collections.Callable): # Return because _render_value() is already a string. return self._render_value(val(), context) diff --git a/pystache/renderer.py b/pystache/renderer.py index ff6a90c6..3bad169e 100644 --- a/pystache/renderer.py +++ b/pystache/renderer.py @@ -32,7 +32,7 @@ class Renderer(object): >>> partials = {'partial': 'Hello, {{thing}}!'} >>> renderer = Renderer(partials=partials) >>> # We apply print to make the test work in Python 3 after 2to3. - >>> print renderer.render('{{>partial}}', {'thing': 'world'}) + >>> print(renderer.render('{{>partial}}', {'thing': 'world'})) Hello, world! To customize string coercion (e.g. to render False values as ''), one can @@ -458,3 +458,4 @@ def render(self, template, *context, **kwargs): # Otherwise, we assume the template is an object. return self._render_object(template, *context, **kwargs) + diff --git a/pystache/tests/benchmark.py b/pystache/tests/benchmark.py index d46e9733..b438d121 100755 --- a/pystache/tests/benchmark.py +++ b/pystache/tests/benchmark.py @@ -76,17 +76,17 @@ def main(sys_argv): args = sys_argv[1:] count = int(args[0]) - print "Benchmarking: %sx" % count - print + print("Benchmarking: %sx" % count) + print() for example in examples: test = make_test_function(example) t = Timer(test,) - print min(t.repeat(repeat=3, number=count)) + print(min(t.repeat(repeat=3, number=count))) - print "Done" + print("Done") if __name__ == '__main__': diff --git a/pystache/tests/common.py b/pystache/tests/common.py index 222e14f2..12b76b52 100644 --- a/pystache/tests/common.py +++ b/pystache/tests/common.py @@ -72,8 +72,8 @@ def _find_files(root_dir, should_include): # http://docs.python.org/library/os.html#os.walk for dir_path, dir_names, file_names in os.walk(root_dir): new_paths = [os.path.join(dir_path, file_name) for file_name in file_names] - new_paths = filter(is_module, new_paths) - new_paths = filter(should_include, new_paths) + new_paths = list(filter(is_module, new_paths)) + new_paths = list(filter(should_include, new_paths)) paths.extend(new_paths) return paths @@ -183,7 +183,7 @@ def assertException(self, exception_type, msg, callable, *args, **kwds): try: callable(*args, **kwds) raise Exception("Expected exception: %s: %s" % (exception_type, repr(msg))) - except exception_type, err: + except exception_type as err: self.assertEqual(str(err), msg) @@ -228,10 +228,10 @@ class Attachable(object): """ def __init__(self, **kwargs): self.__args__ = kwargs - for arg, value in kwargs.iteritems(): + for arg, value in kwargs.items(): setattr(self, arg, value) def __repr__(self): return "%s(%s)" % (self.__class__.__name__, ", ".join("%s=%s" % (k, repr(v)) - for k, v in self.__args__.iteritems())) + for k, v in self.__args__.items())) diff --git a/pystache/tests/main.py b/pystache/tests/main.py index 8af6b2ee..6d6f5c98 100644 --- a/pystache/tests/main.py +++ b/pystache/tests/main.py @@ -88,7 +88,7 @@ def main(sys_argv): """ # TODO: use logging module - print "pystache: running tests: argv: %s" % repr(sys_argv) + print("pystache: running tests: argv: %s" % repr(sys_argv)) should_source_exist = False spec_test_dir = None diff --git a/pystache/tests/spectesting.py b/pystache/tests/spectesting.py index ec8a08df..f9ce744e 100644 --- a/pystache/tests/spectesting.py +++ b/pystache/tests/spectesting.py @@ -37,7 +37,7 @@ from sys import exc_info ex_type, ex_value, tb = exc_info() new_ex = Exception("%s: %s" % (ex_type.__name__, ex_value)) - raise new_ex.__class__, new_ex, tb + raise new_ex.__class__(new_ex).with_traceback(tb) file_extension = 'json' parser = json else: @@ -62,7 +62,7 @@ def get_spec_tests(spec_test_dir): """ # TODO: use logging module instead. - print "pystache: spec tests: using %s" % _get_parser_info() + print("pystache: spec tests: using %s" % _get_parser_info()) cases = [] @@ -133,7 +133,7 @@ def _convert_children(node): return # Otherwise, node is a dict, so attempt the conversion. - for key in node.keys(): + for key in list(node.keys()): val = node[key] if not isinstance(val, dict) or val.get('__tag__') != 'code': @@ -160,7 +160,7 @@ def _deserialize_spec_test(data, file_path): # PyYAML seems to leave ASCII strings as byte strings. expected = unicode(data['expected']) # TODO: switch to using dict.get(). - partials = data.has_key('partials') and data['partials'] or {} + partials = 'partials' in data and data['partials'] or {} template = data['template'] test_name = data['name'] diff --git a/pystache/tests/test___init__.py b/pystache/tests/test___init__.py index eae42c1a..63d2c3bf 100644 --- a/pystache/tests/test___init__.py +++ b/pystache/tests/test___init__.py @@ -6,9 +6,9 @@ """ # Calling "import *" is allowed only at the module level. -GLOBALS_INITIAL = globals().keys() +GLOBALS_INITIAL = list(globals().keys()) from pystache import * -GLOBALS_PYSTACHE_IMPORTED = globals().keys() +GLOBALS_PYSTACHE_IMPORTED = list(globals().keys()) import unittest diff --git a/pystache/tests/test_defaults.py b/pystache/tests/test_defaults.py index c78ea7c8..c23f1967 100644 --- a/pystache/tests/test_defaults.py +++ b/pystache/tests/test_defaults.py @@ -31,7 +31,7 @@ def setUp(self): self.saved[e] = getattr(pystache.defaults, e) def tearDown(self): - for key, value in self.saved.items(): + for key, value in list(self.saved.items()): setattr(pystache.defaults, key, value) def test_tag_escape(self): diff --git a/pystache/tests/test_examples.py b/pystache/tests/test_examples.py index 5c9f74da..159d0370 100644 --- a/pystache/tests/test_examples.py +++ b/pystache/tests/test_examples.py @@ -7,15 +7,15 @@ import unittest -from examples.comments import Comments -from examples.double_section import DoubleSection -from examples.escaped import Escaped -from examples.unescaped import Unescaped -from examples.template_partial import TemplatePartial -from examples.delimiters import Delimiters -from examples.unicode_output import UnicodeOutput -from examples.unicode_input import UnicodeInput -from examples.nested_context import NestedContext +from .examples.comments import Comments +from .examples.double_section import DoubleSection +from .examples.escaped import Escaped +from .examples.unescaped import Unescaped +from .examples.template_partial import TemplatePartial +from .examples.delimiters import Delimiters +from .examples.unicode_output import UnicodeOutput +from .examples.unicode_input import UnicodeInput +from .examples.nested_context import NestedContext from pystache import Renderer from pystache.tests.common import EXAMPLES_DIR from pystache.tests.common import AssertStringMixin diff --git a/pystache/tests/test_renderengine.py b/pystache/tests/test_renderengine.py index db916f77..921b9316 100644 --- a/pystache/tests/test_renderengine.py +++ b/pystache/tests/test_renderengine.py @@ -14,6 +14,7 @@ from pystache.renderer import Renderer from pystache.renderengine import context_get, RenderEngine from pystache.tests.common import AssertStringMixin, AssertExceptionMixin, Attachable +import collections def _get_unicode_char(): @@ -294,7 +295,7 @@ def test_interpolation__falsey__zero(self): def _assert_builtin_attr(self, item, attr_name, expected_attr): self.assertTrue(hasattr(item, attr_name)) actual = getattr(item, attr_name) - if callable(actual): + if isinstance(actual, collections.Callable): actual = actual() self.assertEqual(actual, expected_attr) @@ -440,7 +441,7 @@ def test_section__end_tag_with_no_start_tag(self): template = '{{/section}}' try: self._assert_render(None, template) - except ParsingError, err: + except ParsingError as err: self.assertEqual(str(err), "Section end tag mismatch: section != None") def test_section__end_tag_mismatch(self): @@ -451,7 +452,7 @@ def test_section__end_tag_mismatch(self): template = '{{#section_start}}{{/section_end}}' try: self._assert_render(None, template) - except ParsingError, err: + except ParsingError as err: self.assertEqual(str(err), "Section end tag mismatch: section_end != section_start") def test_section__context_values(self): @@ -577,7 +578,7 @@ def test_section__iterable(self): context = {'iterable': (i for i in range(3))} # type 'generator' self._assert_render(u'012', template, context) - context = {'iterable': xrange(4)} # type 'xrange' + context = {'iterable': range(4)} # type 'xrange' self._assert_render(u'0123', template, context) d = {'foo': 0, 'bar': 0} @@ -586,8 +587,8 @@ def test_section__iterable(self): # "If items(), keys(), values(), iteritems(), iterkeys(), and # itervalues() are called with no intervening modifications to # the dictionary, the lists will directly correspond." - expected = u''.join(d.keys()) - context = {'iterable': d.iterkeys()} # type 'dictionary-keyiterator' + expected = u''.join(list(d.keys())) + context = {'iterable': iter(d.keys())} # type 'dictionary-keyiterator' self._assert_render(expected, template, context) def test_section__lambda__tag_in_output(self): diff --git a/pystache/tests/test_renderer.py b/pystache/tests/test_renderer.py index 0dbe0d99..6d41978d 100644 --- a/pystache/tests/test_renderer.py +++ b/pystache/tests/test_renderer.py @@ -10,7 +10,7 @@ import sys import unittest -from examples.simple import Simple +from .examples.simple import Simple from pystache import Renderer from pystache import TemplateSpec from pystache.common import TemplateNotFoundError diff --git a/pystache/tests/test_simple.py b/pystache/tests/test_simple.py index 07b059f5..6189d90d 100644 --- a/pystache/tests/test_simple.py +++ b/pystache/tests/test_simple.py @@ -2,11 +2,11 @@ import pystache from pystache import Renderer -from examples.nested_context import NestedContext -from examples.complex import Complex -from examples.lambdas import Lambdas -from examples.template_partial import TemplatePartial -from examples.simple import Simple +from .examples.nested_context import NestedContext +from .examples.complex import Complex +from .examples.lambdas import Lambdas +from .examples.template_partial import TemplatePartial +from .examples.simple import Simple from pystache.tests.common import EXAMPLES_DIR from pystache.tests.common import AssertStringMixin diff --git a/pystache/tests/test_specloader.py b/pystache/tests/test_specloader.py index cacc0fc9..af872f42 100644 --- a/pystache/tests/test_specloader.py +++ b/pystache/tests/test_specloader.py @@ -9,11 +9,11 @@ import sys import unittest -import examples -from examples.simple import Simple -from examples.complex import Complex -from examples.lambdas import Lambdas -from examples.inverted import Inverted, InvertedLists +from . import examples +from .examples.simple import Simple +from .examples.complex import Complex +from .examples.lambdas import Lambdas +from .examples.inverted import Inverted, InvertedLists from pystache import Renderer from pystache import TemplateSpec from pystache.common import TemplateNotFoundError From 69716f85e5845ab5a0054a2345a02a3ded9fbe9d Mon Sep 17 00:00:00 2001 From: Daniel Morrison Date: Sun, 21 Sep 2014 23:25:27 -0400 Subject: [PATCH 2/2] unicode and basestring backfill for python3 --- pystache/common.py | 6 ++++++ pystache/loader.py | 5 +++++ pystache/parsed.py | 5 +++++ pystache/parser.py | 9 +++++++-- pystache/renderengine.py | 5 +++++ pystache/renderer.py | 6 ++++++ pystache/tests/common.py | 2 +- pystache/tests/spectesting.py | 5 +++++ pystache/tests/test_loader.py | 5 +++++ pystache/tests/test_renderengine.py | 5 +++++ pystache/tests/test_renderer.py | 5 +++++ pystache/tests/test_specloader.py | 5 +++++ 12 files changed, 60 insertions(+), 3 deletions(-) diff --git a/pystache/common.py b/pystache/common.py index fb266dd8..5bc860e6 100644 --- a/pystache/common.py +++ b/pystache/common.py @@ -7,6 +7,12 @@ from sys import version_info +try: + unicode +except: + unicode = str + + def _get_string_types(): # TODO: come up with a better solution for this. One of the issues here # is that in Python 3 there is no common base class for unicode strings diff --git a/pystache/loader.py b/pystache/loader.py index d4a7e531..b1cd4dbb 100644 --- a/pystache/loader.py +++ b/pystache/loader.py @@ -12,6 +12,11 @@ from pystache import defaults from pystache.locator import Locator +try: + unicode +except: + unicode = str + # We make a function so that the current defaults take effect. # TODO: revisit whether this is necessary. diff --git a/pystache/parsed.py b/pystache/parsed.py index f017dd44..37a1e636 100644 --- a/pystache/parsed.py +++ b/pystache/parsed.py @@ -5,6 +5,11 @@ """ +try: + unicode +except: + unicode = str + class ParsedTemplate(object): diff --git a/pystache/parser.py b/pystache/parser.py index a7a79da9..dd7e69d4 100644 --- a/pystache/parser.py +++ b/pystache/parser.py @@ -11,9 +11,14 @@ from pystache.parsed import ParsedTemplate import collections +try: + unicode +except: + unicode = str + END_OF_LINE_CHARACTERS = [u'\r', u'\n'] -NON_BLANK_RE = re.compile(ur'^(.)', re.M) +NON_BLANK_RE = re.compile(unicode(r'^(.)'), re.M) # TODO: add some unit tests for this. @@ -148,7 +153,7 @@ def __repr__(self): def render(self, engine, context): template = engine.resolve_partial(self.key) # Indent before rendering. - template = re.sub(NON_BLANK_RE, self.indent + ur'\1', template) + template = re.sub(NON_BLANK_RE, self.indent + unicode(r'\1'), template) return engine.render(template, context) diff --git a/pystache/renderengine.py b/pystache/renderengine.py index 564ed743..2c36f991 100644 --- a/pystache/renderengine.py +++ b/pystache/renderengine.py @@ -11,6 +11,11 @@ from pystache.parser import parse import collections +try: + unicode +except: + unicode = str + def context_get(stack, name): """ diff --git a/pystache/renderer.py b/pystache/renderer.py index 3bad169e..c6bcce5c 100644 --- a/pystache/renderer.py +++ b/pystache/renderer.py @@ -16,6 +16,12 @@ from pystache.specloader import SpecLoader from pystache.template_spec import TemplateSpec +try: + unicode +except: + unicode = str + basestring = str + class Renderer(object): diff --git a/pystache/tests/common.py b/pystache/tests/common.py index 12b76b52..05fce639 100644 --- a/pystache/tests/common.py +++ b/pystache/tests/common.py @@ -234,4 +234,4 @@ def __init__(self, **kwargs): def __repr__(self): return "%s(%s)" % (self.__class__.__name__, ", ".join("%s=%s" % (k, repr(v)) - for k, v in self.__args__.items())) + for k, v in sorted(self.__args__.items()))) diff --git a/pystache/tests/spectesting.py b/pystache/tests/spectesting.py index f9ce744e..39afbbd7 100644 --- a/pystache/tests/spectesting.py +++ b/pystache/tests/spectesting.py @@ -55,6 +55,11 @@ from pystache.renderer import Renderer from pystache.tests.common import AssertStringMixin +try: + unicode +except: + unicode = str + def get_spec_tests(spec_test_dir): """ diff --git a/pystache/tests/test_loader.py b/pystache/tests/test_loader.py index f2c21874..fc1b7969 100644 --- a/pystache/tests/test_loader.py +++ b/pystache/tests/test_loader.py @@ -13,6 +13,11 @@ from pystache import defaults from pystache.loader import Loader +try: + unicode +except: + unicode = str + # We use the same directory as the locator tests for now. LOADER_DATA_DIR = os.path.join(DATA_DIR, 'locator') diff --git a/pystache/tests/test_renderengine.py b/pystache/tests/test_renderengine.py index 921b9316..a4085b23 100644 --- a/pystache/tests/test_renderengine.py +++ b/pystache/tests/test_renderengine.py @@ -16,6 +16,11 @@ from pystache.tests.common import AssertStringMixin, AssertExceptionMixin, Attachable import collections +try: + unicode +except: + unicode = str + def _get_unicode_char(): if sys.version_info < (3, ): diff --git a/pystache/tests/test_renderer.py b/pystache/tests/test_renderer.py index 6d41978d..6a7251f4 100644 --- a/pystache/tests/test_renderer.py +++ b/pystache/tests/test_renderer.py @@ -20,6 +20,11 @@ from pystache.tests.common import get_data_path, AssertStringMixin, AssertExceptionMixin from pystache.tests.data.views import SayHello +try: + unicode +except: + unicode = str + def _make_renderer(): """ diff --git a/pystache/tests/test_specloader.py b/pystache/tests/test_specloader.py index af872f42..276b1568 100644 --- a/pystache/tests/test_specloader.py +++ b/pystache/tests/test_specloader.py @@ -25,6 +25,11 @@ from pystache.tests.data.views import SampleView from pystache.tests.data.views import NonAscii +try: + unicode +except: + unicode = str + class Thing(object): pass