Repository: ipython/ipython

Issue:
_ipython_display_, return value, and output prompt behavior
I might have found a strange interaction between `_ipython_display_` the in output prompt system. Given this file:

```python
# tst.py
from IPython import display

class A:
    def __repr__(self):
        return "    A\n0   B"


class B(A):
    def _ipython_display_(self):
        data = {'text/plain': repr(self)}
        display.display(data, raw=True)

class C(B):
    def _ipython_display_(self):
        super()._ipython_display_()
        return "C"
```

Here's the output:

```python
In [1]: from tst import *

In [2]: A()
Out[2]:
    A
0   B

In [3]: B()
Out[3]:     A
0   B

In [4]: C()
Out[4]:     A
0   B
```

I think the correct output for `In[3]` is just the `repr(self)`, but no `Out[3]` tag, since nothing is returned? I have no idea what the correct output of `In[4]` is, but maybe

```     
    A  # the super
0   B
"C"  # the return value of C._ipython_display_()
```
but I don't know if / where the `Out[4]` tag would go.

For background, we're working on a table schema repr for pandas in https://github.com/pandas-dev/pandas/pull/14904.

This is on IPython master from about 3 weeks ago.

cc @minrk 


Discussion:

Resolving patch:
diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py
--- a/IPython/terminal/interactiveshell.py
+++ b/IPython/terminal/interactiveshell.py
@@ -203,6 +203,8 @@ def init_display_formatter(self):
         super(TerminalInteractiveShell, self).init_display_formatter()
         # terminal only supports plain text
         self.display_formatter.active_types = ['text/plain']
+        # disable `_ipython_display_`
+        self.display_formatter.ipython_display_formatter.enabled = False
 
     def init_prompt_toolkit_cli(self):
         if self.simple_prompt:


Test patch:
diff --git a/IPython/core/tests/test_formatters.py b/IPython/core/tests/test_formatters.py
--- a/IPython/core/tests/test_formatters.py
+++ b/IPython/core/tests/test_formatters.py
@@ -407,6 +407,9 @@ def __repr__(self):
         def _ipython_display_(self):
             raise NotImplementedError
     
+    save_enabled = f.ipython_display_formatter.enabled
+    f.ipython_display_formatter.enabled = True
+    
     yes = SelfDisplaying()
     no = NotSelfDisplaying()
     
@@ -420,6 +423,9 @@ def _ipython_display_(self):
     nt.assert_equal(md, {})
     nt.assert_equal(catcher, [yes])
 
+    f.ipython_display_formatter.enabled = save_enabled
+
+
 def test_json_as_string_deprecated():
     class JSONString(object):
         def _repr_json_(self):
diff --git a/IPython/terminal/tests/test_interactivshell.py b/IPython/terminal/tests/test_interactivshell.py
--- a/IPython/terminal/tests/test_interactivshell.py
+++ b/IPython/terminal/tests/test_interactivshell.py
@@ -1,17 +1,14 @@
 # -*- coding: utf-8 -*-
 """Tests for the TerminalInteractiveShell and related pieces."""
-#-----------------------------------------------------------------------------
-#  Copyright (C) 2011  The IPython Development Team
-#
-#  Distributed under the terms of the BSD License.  The full license is in
-#  the file COPYING, distributed as part of this software.
-#-----------------------------------------------------------------------------
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
 
 import sys
 import unittest
 
 from IPython.core.inputtransformer import InputTransformer
 from IPython.testing import tools as tt
+from IPython.utils.capture import capture_output
 
 # Decorator for interaction loop tests -----------------------------------------
 
@@ -99,6 +96,33 @@ def test_plain_text_only(self):
         ip = get_ipython()
         formatter = ip.display_formatter
         assert formatter.active_types == ['text/plain']
+        assert not formatter.ipython_display_formatter.enabled
+
+        class Test(object):
+            def __repr__(self):
+                return "<Test %i>" % id(self)
+
+            def _repr_html_(self):
+                return '<html>'
+
+        # verify that HTML repr isn't computed
+        obj = Test()
+        data, _ = formatter.format(obj)
+        self.assertEqual(data, {'text/plain': repr(obj)})
+
+        class Test2(Test):
+            def _ipython_display_(self):
+                from IPython.display import display
+                display('<custom>')
+
+        # verify that _ipython_display_ shortcut isn't called
+        obj = Test2()
+        with capture_output() as captured:
+            data, _ = formatter.format(obj)
+
+        self.assertEqual(data, {'text/plain': repr(obj)})
+        assert captured.stdout == ''
+
 
 
 class SyntaxErrorTransformer(InputTransformer):