Improved error message for undefineds

--HG--
branch : trunk
diff --git a/jinja2/runtime.py b/jinja2/runtime.py
index 16389e0..1961e9f 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 @@
             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 @@
             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 4134d26..dfd8b64 100644
--- a/jinja2/testsuite/api.py
+++ b/jinja2/testsuite/api.py
@@ -207,11 +207,19 @@
         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 1fd6ec5..0ba86e7 100644
--- a/jinja2/utils.py
+++ b/jinja2/utils.py
@@ -227,6 +227,22 @@
             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`.