Repository: explosion/spaCy

Issue:
Spacy import breaks pandas output in jupyter
## How to reproduce the behaviour
<!-- Include a code example or the steps that led to the problem. Please try to be as specific as possible. -->

```python
# In[1]:
import pandas as pd
import numpy as np

# In[2]:
df = pd.DataFrame(np.ones((2, 2)))

# In[3]:
df  # shows the dataframe

# In[4]:
import spacy

# In[5]:
df  # leads to an exception
```

## Your Environment
<!-- Include details of your environment. If you're using spaCy 1.7+, you can also type `python -m spacy info --markdown` and copy-paste the result here.-->
* **spaCy version:** 2.0.16
* **Platform:** Linux-4.15.0-43-generic-x86_64-with-debian-buster-sid
* **Python version:** 3.7.0
* **Models:** en, en_core_web_lg

## Notes
This only affects pandas 0.24.0 (0.23.4 works fine). Functions like `.head()` are also affected.
Exception details:

```python
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~/anaconda3/envs/fat_ml/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
    343             method = get_real_method(obj, self.print_method)
    344             if method is not None:
--> 345                 return method()
    346             return None
    347         else:

~/anaconda3/envs/fat_ml/lib/python3.7/site-packages/pandas/core/frame.py in _repr_html_(self)
    647         # display HTML, so this check can be removed when support for
    648         # IPython 2.x is no longer needed.
--> 649         if console.in_qtconsole():
    650             # 'HTML output is disabled in QtConsole'
    651             return None

~/anaconda3/envs/fat_ml/lib/python3.7/site-packages/pandas/io/formats/console.py in in_qtconsole()
    121             ip.config.get('KernelApp', {}).get('parent_appname', "") or
    122             ip.config.get('IPKernelApp', {}).get('parent_appname', ""))
--> 123         if 'qtconsole' in front_end.lower():
    124             return True
    125     except NameError:

AttributeError: 'LazyConfigValue' object has no attribute 'lower'
```
Spacy import breaks pandas output in jupyter
## How to reproduce the behaviour
<!-- Include a code example or the steps that led to the problem. Please try to be as specific as possible. -->

```python
# In[1]:
import pandas as pd
import numpy as np

# In[2]:
df = pd.DataFrame(np.ones((2, 2)))

# In[3]:
df  # shows the dataframe

# In[4]:
import spacy

# In[5]:
df  # leads to an exception
```

## Your Environment
<!-- Include details of your environment. If you're using spaCy 1.7+, you can also type `python -m spacy info --markdown` and copy-paste the result here.-->
* **spaCy version:** 2.0.16
* **Platform:** Linux-4.15.0-43-generic-x86_64-with-debian-buster-sid
* **Python version:** 3.7.0
* **Models:** en, en_core_web_lg

## Notes
This only affects pandas 0.24.0 (0.23.4 works fine). Functions like `.head()` are also affected.
Exception details:

```python
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~/anaconda3/envs/fat_ml/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
    343             method = get_real_method(obj, self.print_method)
    344             if method is not None:
--> 345                 return method()
    346             return None
    347         else:

~/anaconda3/envs/fat_ml/lib/python3.7/site-packages/pandas/core/frame.py in _repr_html_(self)
    647         # display HTML, so this check can be removed when support for
    648         # IPython 2.x is no longer needed.
--> 649         if console.in_qtconsole():
    650             # 'HTML output is disabled in QtConsole'
    651             return None

~/anaconda3/envs/fat_ml/lib/python3.7/site-packages/pandas/io/formats/console.py in in_qtconsole()
    121             ip.config.get('KernelApp', {}).get('parent_appname', "") or
    122             ip.config.get('IPKernelApp', {}).get('parent_appname', ""))
--> 123         if 'qtconsole' in front_end.lower():
    124             return True
    125     except NameError:

AttributeError: 'LazyConfigValue' object has no attribute 'lower'
```


Discussion:

Resolving patch:
diff --git a/spacy/displacy/__init__.py b/spacy/displacy/__init__.py
--- a/spacy/displacy/__init__.py
+++ b/spacy/displacy/__init__.py
@@ -9,10 +9,9 @@
 
 
 _html = {}
-IS_JUPYTER = is_in_jupyter()
 
 
-def render(docs, style='dep', page=False, minify=False, jupyter=IS_JUPYTER,
+def render(docs, style='dep', page=False, minify=False, jupyter=False,
            options={}, manual=False):
     """Render displaCy visualisation.
 
@@ -39,7 +38,7 @@ def render(docs, style='dep', page=False, minify=False, jupyter=IS_JUPYTER,
     parsed = [converter(doc, options) for doc in docs] if not manual else docs
     _html['parsed'] = renderer.render(parsed, page=page, minify=minify).strip()
     html = _html['parsed']
-    if jupyter:  # return HTML rendered by IPython display()
+    if jupyter or is_in_jupyter():  # return HTML rendered by IPython display()
         from IPython.core.display import display, HTML
         return display(HTML(html))
     return html
diff --git a/spacy/util.py b/spacy/util.py
--- a/spacy/util.py
+++ b/spacy/util.py
@@ -222,15 +222,15 @@ def get_package_path(name):
 def is_in_jupyter():
     """Check if user is running spaCy from a Jupyter notebook by detecting the
     IPython kernel. Mainly used for the displaCy visualizer.
-
     RETURNS (bool): True if in Jupyter, False if not.
     """
+    # https://stackoverflow.com/a/39662359/6400719
     try:
-        cfg = get_ipython().config
-        if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
-            return True
+        shell = get_ipython().__class__.__name__
+        if shell == "ZMQInteractiveShell":
+            return True  # Jupyter notebook or qtconsole
     except NameError:
-        return False
+        return False  # Probably standard Python interpreter
     return False
 
 


Test patch: