Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simultaneous Python 2 and Python 3 support. #169

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pystache/commands/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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__':
Expand Down
6 changes: 6 additions & 0 deletions pystache/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion pystache/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""

from pystache.common import PystacheError
import collections


# This equals '__builtin__' in Python 2 and 'builtins' in Python 3.
Expand Down Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions pystache/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion pystache/parsed.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

"""

try:
unicode
except:
unicode = str


class ParsedTemplate(object):

Expand Down Expand Up @@ -44,7 +49,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)
15 changes: 11 additions & 4 deletions pystache/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@

from pystache import defaults
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.
Expand All @@ -31,7 +37,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'), '!'])]

"""
Expand Down Expand Up @@ -147,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)

Expand Down Expand Up @@ -193,7 +199,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--
#
Expand Down Expand Up @@ -376,3 +382,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))

8 changes: 7 additions & 1 deletion pystache/renderengine.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

from pystache.common import is_string
from pystache.parser import parse
import collections

try:
unicode
except:
unicode = str


def context_get(stack, name):
Expand Down Expand Up @@ -104,7 +110,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)

Expand Down
9 changes: 8 additions & 1 deletion pystache/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):

Expand All @@ -32,7 +38,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
Expand Down Expand Up @@ -458,3 +464,4 @@ def render(self, template, *context, **kwargs):
# Otherwise, we assume the template is an object.

return self._render_object(template, *context, **kwargs)

8 changes: 4 additions & 4 deletions pystache/tests/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__':
Expand Down
10 changes: 5 additions & 5 deletions pystache/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)


Expand Down Expand Up @@ -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 sorted(self.__args__.items())))
2 changes: 1 addition & 1 deletion pystache/tests/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 9 additions & 4 deletions pystache/tests/spectesting.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -55,14 +55,19 @@
from pystache.renderer import Renderer
from pystache.tests.common import AssertStringMixin

try:
unicode
except:
unicode = str


def get_spec_tests(spec_test_dir):
"""
Return a list of unittest.TestCase instances.

"""
# TODO: use logging module instead.
print "pystache: spec tests: using %s" % _get_parser_info()
print("pystache: spec tests: using %s" % _get_parser_info())

cases = []

Expand Down Expand Up @@ -133,7 +138,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':
Expand All @@ -160,7 +165,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']

Expand Down
4 changes: 2 additions & 2 deletions pystache/tests/test___init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion pystache/tests/test_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
18 changes: 9 additions & 9 deletions pystache/tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions pystache/tests/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Loading