Permalink
Browse files

Addressed issue #115: "Match spec expectation for partials not found"

  • Loading branch information...
cjerdonek committed May 3, 2012
1 parent 27f2ae7 commit 5a94c93b9ad263bf8497576ca4a5b8b0ca4cd581
View
@@ -5,6 +5,7 @@ History
-----------
* Added support for dot notation and version 1.1.2 of the spec (issue #99). [rbp]
+* Missing partials now render as empty string per latest version of spec (issue #115).
* Bugfix: falsey values now coerced to strings using str().
* Bugfix: lambda return values for sections no longer pushed onto context stack (issue #113).
* Bugfix: lists of lambdas for sections were not rendered (issue #114).
@@ -35,6 +35,7 @@
#
# ValueError: Attempted relative import in non-package
#
+from pystache.common import TemplateNotFoundError
from pystache.renderer import Renderer
@@ -78,7 +79,7 @@ def main(sys_argv=sys.argv):
try:
template = renderer.load_template(template)
- except IOError:
+ except TemplateNotFoundError:
pass
try:
View
@@ -1,7 +1,7 @@
# coding: utf-8
"""
-Exposes common functions.
+Exposes functionality needed throughout the project.
"""
@@ -24,3 +24,13 @@ def read(path):
return f.read()
finally:
f.close()
+
+
+class PystacheError(Exception):
+ """Base class for Pystache exceptions."""
+ pass
+
+
+class TemplateNotFoundError(PystacheError):
+ """An exception raised when a template is not found."""
+ pass
View
@@ -9,6 +9,7 @@
import re
import sys
+from pystache.common import TemplateNotFoundError
from pystache import defaults
@@ -117,9 +118,8 @@ def _find_path_required(self, search_dirs, file_name):
path = self._find_path(search_dirs, file_name)
if path is None:
- # TODO: we should probably raise an exception of our own type.
- raise IOError('Template file %s not found in directories: %s' %
- (repr(file_name), repr(search_dirs)))
+ raise TemplateNotFoundError('File %s not found in dirs: %s' %
+ (repr(file_name), repr(search_dirs)))
return path
View
@@ -32,6 +32,9 @@ def __init__(self, parse_tree):
"""
self._parse_tree = parse_tree
+ def __repr__(self):
+ return "[%s]" % (", ".join([repr(part) for part in self._parse_tree]))
+
def render(self, context):
"""
Returns: a string of type unicode.
View
@@ -9,12 +9,13 @@
import re
+from pystache.common import TemplateNotFoundError
from pystache.parsed import ParsedTemplate
-DEFAULT_DELIMITERS = ('{{', '}}')
-END_OF_LINE_CHARACTERS = ['\r', '\n']
-NON_BLANK_RE = re.compile(r'^(.)', re.M)
+DEFAULT_DELIMITERS = (u'{{', u'}}')
+END_OF_LINE_CHARACTERS = [u'\r', u'\n']
+NON_BLANK_RE = re.compile(ur'^(.)', re.M)
def _compile_template_re(delimiters=None):
@@ -215,10 +216,14 @@ def _handle_tag_type(self, template, parse_tree, tag_type, tag_key, leading_whit
elif tag_type == '>':
- template = engine.load_partial(tag_key)
+ try:
+ # TODO: make engine.load() and test it separately.
+ template = engine.load_partial(tag_key)
+ except TemplateNotFoundError:
+ template = u''
# Indent before rendering.
- template = re.sub(NON_BLANK_RE, leading_whitespace + r'\1', template)
+ template = re.sub(NON_BLANK_RE, leading_whitespace + ur'\1', template)
func = engine._make_get_partial(template)
View
@@ -35,7 +35,8 @@ def __init__(self, load_partial=None, literal=None, escape=None):
load_partial: the function to call when loading a partial. The
function should accept a string template name and return a
- template string of type unicode (not a subclass).
+ template string of type unicode (not a subclass). If the
+ template is not found, it should raise a TemplateNotFoundError.
literal: the function used to convert unescaped variable tag
values to unicode, e.g. the value corresponding to a tag
View
@@ -8,6 +8,7 @@
import sys
from pystache import defaults
+from pystache.common import TemplateNotFoundError
from pystache.context import ContextStack
from pystache.loader import Loader
from pystache.renderengine import RenderEngine
@@ -239,9 +240,8 @@ def load_partial(name):
template = partials.get(name)
if template is None:
- # TODO: make a TemplateNotFoundException type that provides
- # the original partials as an attribute.
- raise Exception("Partial not found with name: %s" % repr(name))
+ raise TemplateNotFoundError("Name %s not found in partials: %s" %
+ (repr(name), type(partials)))
# RenderEngine requires that the return value be unicode.
return self._to_unicode_hard(template)
View
@@ -168,6 +168,20 @@ def assertIs(self, first, second):
self.assertTrue(first is second, msg="%s is not %s" % (repr(first), repr(second)))
+class AssertExceptionMixin:
+
+ """A unittest.TestCase mixin adding assertException()."""
+
+ # unittest.assertRaisesRegexp() is not available until Python 2.7:
+ # http://docs.python.org/library/unittest.html#unittest.TestCase.assertRaisesRegexp
+ 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:
+ self.assertEqual(str(err), msg)
+
+
class SetupDefaults(object):
"""
@@ -11,14 +11,15 @@
import unittest
# TODO: remove this alias.
+from pystache.common import TemplateNotFoundError
from pystache.loader import Loader as Reader
from pystache.locator import Locator
-from pystache.tests.common import DATA_DIR, EXAMPLES_DIR
+from pystache.tests.common import DATA_DIR, EXAMPLES_DIR, AssertExceptionMixin
from pystache.tests.data.views import SayHello
-class LocatorTests(unittest.TestCase):
+class LocatorTests(unittest.TestCase, AssertExceptionMixin):
def _locator(self):
return Locator(search_dirs=DATA_DIR)
@@ -110,7 +111,8 @@ def test_find_name__precedence(self):
def test_find_name__non_existent_template_fails(self):
locator = Locator()
- self.assertRaises(IOError, locator.find_name, search_dirs=[], template_name='doesnt_exist')
+ self.assertException(TemplateNotFoundError, "File 'doesnt_exist.mustache' not found in dirs: []",
+ locator.find_name, search_dirs=[], template_name='doesnt_exist')
def test_find_object(self):
locator = Locator()
@@ -13,9 +13,10 @@
from examples.simple import Simple
from pystache import Renderer
from pystache import TemplateSpec
+from pystache.common import TemplateNotFoundError
from pystache.loader import Loader
-from pystache.tests.common import get_data_path, AssertStringMixin
+from pystache.tests.common import get_data_path, AssertStringMixin, AssertExceptionMixin
from pystache.tests.data.views import SayHello
@@ -405,7 +406,7 @@ def test_render__view(self):
# we no longer need to exercise all rendering code paths through
# the Renderer. It suffices to test rendering paths through the
# RenderEngine for the same amount of code coverage.
-class Renderer_MakeRenderEngineTests(unittest.TestCase):
+class Renderer_MakeRenderEngineTests(unittest.TestCase, AssertExceptionMixin):
"""
Check the RenderEngine returned by Renderer._make_render_engine().
@@ -444,7 +445,20 @@ class MyUnicode(unicode):
self.assertEqual(actual, "abc")
self.assertEqual(type(actual), unicode)
- def test__load_partial__not_found(self):
+ def test__load_partial__not_found__default(self):
+ """
+ Check that load_partial provides a nice message when a template is not found.
+
+ """
+ renderer = Renderer()
+
+ engine = renderer._make_render_engine()
+ load_partial = engine.load_partial
+
+ self.assertException(TemplateNotFoundError, "File 'foo.mustache' not found in dirs: ['.']",
+ load_partial, "foo")
+
+ def test__load_partial__not_found__dict(self):
"""
Check that load_partial provides a nice message when a template is not found.
@@ -455,11 +469,10 @@ def test__load_partial__not_found(self):
engine = renderer._make_render_engine()
load_partial = engine.load_partial
- try:
- load_partial("foo")
- raise Exception("Shouldn't get here")
- except Exception, err:
- self.assertEqual(str(err), "Partial not found with name: 'foo'")
+ # Include dict directly since str(dict) is different in Python 2 and 3:
+ # <type 'dict'> versus <class 'dict'>, respectively.
+ self.assertException(TemplateNotFoundError, "Name 'foo' not found in partials: %s" % dict,
+ load_partial, "foo")
## Test the engine's literal attribute.
@@ -16,6 +16,7 @@
from examples.inverted import Inverted, InvertedLists
from pystache import Renderer
from pystache import TemplateSpec
+from pystache.common import TemplateNotFoundError
from pystache.locator import Locator
from pystache.loader import Loader
from pystache.specloader import SpecLoader
@@ -42,7 +43,7 @@ class Tagless(TemplateSpec):
view = Tagless()
renderer = Renderer()
- self.assertRaises(IOError, renderer.render, view)
+ self.assertRaises(TemplateNotFoundError, renderer.render, view)
# TODO: change this test to remove the following brittle line.
view.template_rel_directory = "examples"
@@ -60,7 +61,8 @@ def test_template_path_for_partials(self):
renderer1 = Renderer()
renderer2 = Renderer(search_dirs=EXAMPLES_DIR)
- self.assertRaises(IOError, renderer1.render, spec)
+ actual = renderer1.render(spec)
+ self.assertString(actual, u"Partial: ")
actual = renderer2.render(spec)
self.assertEqual(actual, "Partial: No tags...")

1 comment on commit 5a94c93

WuLex commented on 5a94c93 Oct 23, 2012

中国

Please sign in to comment.