diff --git a/jinja2/runtime.py b/jinja2/runtime.py index 16389e04e..1961e9f12 100644 --- a/jinja2/runtime.py +++ b/jinja2/runtime.py @@ -12,7 +12,8 @@ from itertools import chain, imap from jinja2.nodes import EvalContext from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \ - concat, MethodType, FunctionType, internalcode, next + concat, MethodType, FunctionType, internalcode, next, \ + object_type_repr from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ TemplateNotFound @@ -437,13 +438,13 @@ def _fail_with_undefined_error(self, *args, **kwargs): if self._undefined_obj is missing: hint = '%r is undefined' % self._undefined_name elif not isinstance(self._undefined_name, basestring): - hint = '%r object has no element %r' % ( - self._undefined_obj.__class__.__name__, + hint = '%s has no element %r' % ( + object_type_repr(self._undefined_obj), self._undefined_name ) else: - hint = '%r object has no attribute %r' % ( - self._undefined_obj.__class__.__name__, + hint = '%r has no attribute %r' % ( + object_type_repr(self._undefined_obj), self._undefined_name ) else: @@ -501,7 +502,7 @@ def __unicode__(self): if self._undefined_obj is missing: return u'{{ %s }}' % self._undefined_name return '{{ no such element: %s[%r] }}' % ( - self._undefined_obj.__class__.__name__, + object_type_repr(self._undefined_obj), self._undefined_name ) return u'{{ undefined value printed: %s }}' % self._undefined_hint diff --git a/jinja2/testsuite/api.py b/jinja2/testsuite/api.py index 4134d2622..dfd8b640f 100644 --- a/jinja2/testsuite/api.py +++ b/jinja2/testsuite/api.py @@ -207,11 +207,19 @@ def test_indexing_gives_undefined(self): t = Template("{{ var[42].foo }}") assert_raises(UndefinedError, t.render, var=0) - def test_none_gives_propert_error(self): + def test_none_gives_proper_error(self): try: - Undefined(None).split() + Environment().getattr(None, 'split') except UndefinedError, e: - assert e.message == 'None is not defined' + assert e.message == "None has no attribute 'split'" + else: + assert False, 'expected exception' + + def test_object_repr(self): + try: + Undefined(obj=42, name='upper') + except UndefinedError, e: + assert e.message == "'int' object has no attribute 'upper'" else: assert False, 'expected exception' diff --git a/jinja2/utils.py b/jinja2/utils.py index 1fd6ec5df..0ba86e768 100644 --- a/jinja2/utils.py +++ b/jinja2/utils.py @@ -227,6 +227,22 @@ def open_if_exists(filename, mode='rb'): raise +def object_type_repr(obj): + """Returns the name of the object's type. For some recognized + singletons the name of the object is returned instead. (For + example for `None` and `Ellipsis`). + """ + if obj is None: + return 'None' + elif obj is Ellipsis: + return 'Ellipsis' + if obj.__class__.__module__ == '__builtin__': + name = obj.__name__ + else: + name = obj.__class__.module__ + '.' + obj.__name__ + return '%s object' % name + + def pformat(obj, verbose=False): """Prettyprint an object. Either use the `pretty` library or the builtin `pprint`.