Repository: ipython/ipython

Issue:
Notebook prints classes without regard to __repr__
Displaying a class that is an instance of a metaclass is done with no regard to the metaclass's **repr**. This is much unexpected and different from what the Python REPL would do.

See [example notebook](http://nbviewer.ipython.org/gist/remram44/11389cfe653eeceddc0f)



Discussion:
seem to be due to [pretty print formatters](https://github.com/ipython/ipython/blob/master/IPython/lib/pretty.py#L681-L691) which get called from [here](https://github.com/ipython/ipython/blob/master/IPython/lib/pretty.py#L385) 

I'm not sure how you can test wether the `__repr__` has been set for the metaclass without always getting true. `type(eraseme.String).__mro__[0].__dict__['__repr__'](eraseme.String)` with some more heuristic if `__mro__[0]` is built-in ?

I think you can do it without all that: `type(String).__repr__ is type.__repr__`. Unless I'm missing something.


Resolving patch:
diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py
--- a/IPython/lib/pretty.py
+++ b/IPython/lib/pretty.py
@@ -517,11 +517,7 @@ def _default_pprint(obj, p, cycle):
     klass = _safe_getattr(obj, '__class__', None) or type(obj)
     if _safe_getattr(klass, '__repr__', None) not in _baseclass_reprs:
         # A user-provided repr. Find newlines and replace them with p.break_()
-        output = repr(obj)
-        for idx,output_line in enumerate(output.splitlines()):
-            if idx:
-                p.break_()
-            p.text(output_line)
+        _repr_pprint(obj, p, cycle)
         return
     p.begin_group(1, '<')
     p.pretty(klass)
@@ -682,6 +678,12 @@ def _type_pprint(obj, p, cycle):
     """The pprint for classes and types."""
     # Heap allocated types might not have the module attribute,
     # and others may set it to None.
+
+    # Checks for a __repr__ override in the metaclass
+    if type(obj).__repr__ is not type.__repr__:
+        _repr_pprint(obj, p, cycle)
+        return
+
     mod = _safe_getattr(obj, '__module__', None)
     name = _safe_getattr(obj, '__qualname__', obj.__name__)
 
@@ -693,7 +695,12 @@ def _type_pprint(obj, p, cycle):
 
 def _repr_pprint(obj, p, cycle):
     """A pprint that just redirects to the normal repr function."""
-    p.text(repr(obj))
+    # Find newlines and replace them with p.break_()
+    output = repr(obj)
+    for idx,output_line in enumerate(output.splitlines()):
+        if idx:
+            p.break_()
+        p.text(output_line)
 
 
 def _function_pprint(obj, p, cycle):


Test patch:
diff --git a/IPython/lib/tests/test_pretty.py b/IPython/lib/tests/test_pretty.py
--- a/IPython/lib/tests/test_pretty.py
+++ b/IPython/lib/tests/test_pretty.py
@@ -11,6 +11,12 @@
 # Our own imports
 from IPython.lib import pretty
 from IPython.testing.decorators import skip_without
+from IPython.utils.py3compat import PY3
+
+if PY3:
+    from io import StringIO
+else:
+    from StringIO import StringIO
 
 
 class MyList(object):
@@ -213,4 +219,38 @@ def test_long_dict():
 
 def test_unbound_method():
     output = pretty.pretty(MyObj.somemethod)
-    nt.assert_in('MyObj.somemethod', output)
\ No newline at end of file
+    nt.assert_in('MyObj.somemethod', output)
+
+
+class MetaClass(type):
+    def __new__(cls, name):
+        return type.__new__(cls, name, (object,), {'name': name})
+
+    def __repr__(self):
+        return "[CUSTOM REPR FOR CLASS %s]" % self.name
+
+
+ClassWithMeta = MetaClass('ClassWithMeta')
+
+
+def test_metaclass_repr():
+    output = pretty.pretty(ClassWithMeta)
+    nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]")
+
+
+def test_basic_class():
+    def type_pprint_wrapper(obj, p, cycle):
+        if obj is MyObj:
+            type_pprint_wrapper.called = True
+        return pretty._type_pprint(obj, p, cycle)
+    type_pprint_wrapper.called = False
+
+    stream = StringIO()
+    printer = pretty.RepresentationPrinter(stream)
+    printer.type_pprinters[type] = type_pprint_wrapper
+    printer.pretty(MyObj)
+    printer.flush()
+    output = stream.getvalue()
+
+    nt.assert_equal(output, '%s.MyObj' % __name__)
+    nt.assert_true(type_pprint_wrapper.called)