Repository: spyder-ide/spyder

Issue:
When browsing MultiIndex in Object Explorer, Pandas raises NotImplementedError: isna is not defined for MultiIndex
## Description of your problem

While inspecting a MultiIndex object in the Object Explorer, scrolling the dialog (i.e. calling ``fetchMore``) causes an error to be thrown when ``getattr`` is called on a certain MultiIndex object, due to it in turn calling ``isna``/``isnan`` in Pandas and throwing an error. This might actually be a corner case ``pandas`` bug, but regardless it should be possible to avoid with a little work, though it can probably just be caught and ``pass``ed even easier with no ill effects. 

I should be able to get to it in 3.2.8, but I'm leaving this here to remind me and document the issue, and if anyone thinks I should report it to pandas instead (i.e. ``__get__`` shouldn't be calling a ``isna`` for ``MultiIndex``) then I'll do so.


Minimal-ish code to reproduce:
```
time_deltas = [pd.Timedelta(minutes=minute)
               for minute in np.arange(start=5, stop=30, step=5)]
    
prediction_index = pd.MultiIndex.from_product([[0, 1, 2, 3, 4], time_deltas])
```

**What steps will reproduce the problem?**

1. Run above code snippit
2. Open ``prediction_index`` in Variable Explorer
3. Scroll resulting dialog

**Traceback**

NotImplementedError: isna is not defined for MultiIndex
Traceback (most recent call last):
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\spyder\widgets\variableexplorer\collectionseditor.py", line 244, in fetchMore
    self.rows_loaded + items_to_fetch)
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\spyder\widgets\variableexplorer\collectionseditor.py", line 178, in set_size_and_type
    for index in range(start, stop) ]
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\spyder\widgets\variableexplorer\collectionseditor.py", line 178, in <listcomp>
    for index in range(start, stop) ]
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\spyder\widgets\variableexplorer\collectionseditor.py", line 78, in __getitem__
    return getattr(self.__obj__, key)
  File "pandas/_libs/properties.pyx", line 38, in pandas._libs.properties.cache_readonly.__get__
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\pandas\core\indexes\base.py", line 1866, in _isnan
    return isna(self)
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\pandas\core\dtypes\missing.py", line 45, in isna
    return _isna(obj)
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\pandas\core\dtypes\missing.py", line 56, in _isna_new
    raise NotImplementedError("isna is not defined for MultiIndex")
NotImplementedError: isna is not defined for MultiIndex


## Versions and main components

* Spyder Version: 3.2.6
* Python Version: 3.6.4
* Qt Version: 5.6.2
* PyQt Version: 5.6
* Operating system: Windows 10 and Windows 8.1


## Dependencies

IPython >=4.0    :  6.1.0 (OK)
cython >=0.21    :  0.27.3 (OK)
jedi >=0.9.0     :  0.10.2 (OK)
nbconvert >=4.0  :  5.3.1 (OK)
numpy >=1.7      :  1.13.3 (OK)
pandas >=0.13.1  :  0.22.0 (OK)
pycodestyle >=2.3:  2.3.1 (OK)
pyflakes >=0.6.0 :  1.6.0 (OK)
pygments >=2.0   :  2.2.0 (OK)
pylint >=0.25    :  1.7.4 (OK)
qtconsole >=4.2.0:  4.3.1 (OK)
rope >=0.9.4     :  0.10.5 (OK)
sphinx >=0.6.6   :  1.6.3 (OK)
sympy >=0.7.3    :  1.1.1 (OK)

When browsing MultiIndex in Object Explorer, Pandas raises NotImplementedError: isna is not defined for MultiIndex
## Description of your problem

While inspecting a MultiIndex object in the Object Explorer, scrolling the dialog (i.e. calling ``fetchMore``) causes an error to be thrown when ``getattr`` is called on a certain MultiIndex object, due to it in turn calling ``isna``/``isnan`` in Pandas and throwing an error. This might actually be a corner case ``pandas`` bug, but regardless it should be possible to avoid with a little work, though it can probably just be caught and ``pass``ed even easier with no ill effects. 

I should be able to get to it in 3.2.8, but I'm leaving this here to remind me and document the issue, and if anyone thinks I should report it to pandas instead (i.e. ``__get__`` shouldn't be calling a ``isna`` for ``MultiIndex``) then I'll do so.


Minimal-ish code to reproduce:
```
time_deltas = [pd.Timedelta(minutes=minute)
               for minute in np.arange(start=5, stop=30, step=5)]
    
prediction_index = pd.MultiIndex.from_product([[0, 1, 2, 3, 4], time_deltas])
```

**What steps will reproduce the problem?**

1. Run above code snippit
2. Open ``prediction_index`` in Variable Explorer
3. Scroll resulting dialog

**Traceback**

NotImplementedError: isna is not defined for MultiIndex
Traceback (most recent call last):
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\spyder\widgets\variableexplorer\collectionseditor.py", line 244, in fetchMore
    self.rows_loaded + items_to_fetch)
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\spyder\widgets\variableexplorer\collectionseditor.py", line 178, in set_size_and_type
    for index in range(start, stop) ]
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\spyder\widgets\variableexplorer\collectionseditor.py", line 178, in <listcomp>
    for index in range(start, stop) ]
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\spyder\widgets\variableexplorer\collectionseditor.py", line 78, in __getitem__
    return getattr(self.__obj__, key)
  File "pandas/_libs/properties.pyx", line 38, in pandas._libs.properties.cache_readonly.__get__
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\pandas\core\indexes\base.py", line 1866, in _isnan
    return isna(self)
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\pandas\core\dtypes\missing.py", line 45, in isna
    return _isna(obj)
  File "C:\Users\christopher.gerlach\Anaconda3\lib\site-packages\pandas\core\dtypes\missing.py", line 56, in _isna_new
    raise NotImplementedError("isna is not defined for MultiIndex")
NotImplementedError: isna is not defined for MultiIndex


## Versions and main components

* Spyder Version: 3.2.6
* Python Version: 3.6.4
* Qt Version: 5.6.2
* PyQt Version: 5.6
* Operating system: Windows 10 and Windows 8.1


## Dependencies

IPython >=4.0    :  6.1.0 (OK)
cython >=0.21    :  0.27.3 (OK)
jedi >=0.9.0     :  0.10.2 (OK)
nbconvert >=4.0  :  5.3.1 (OK)
numpy >=1.7      :  1.13.3 (OK)
pandas >=0.13.1  :  0.22.0 (OK)
pycodestyle >=2.3:  2.3.1 (OK)
pyflakes >=0.6.0 :  1.6.0 (OK)
pygments >=2.0   :  2.2.0 (OK)
pylint >=0.25    :  1.7.4 (OK)
qtconsole >=4.2.0:  4.3.1 (OK)
rope >=0.9.4     :  0.10.5 (OK)
sphinx >=0.6.6   :  1.6.3 (OK)
sympy >=0.7.3    :  1.1.1 (OK)



Discussion:
Just a note: this example could not reproduce the bug on master following the major modifications to the dataframe editor (which now supports multiindexes). Still, it is worth catching that bug in `3.x`.
Its likely because the dataframeeditor is properly used to view multindexes instead of the collection editor as a generic object, avoiding calling the problem method on the item triggering it.
Just a note: this example could not reproduce the bug on master following the major modifications to the dataframe editor (which now supports multiindexes). Still, it is worth catching that bug in `3.x`.
Its likely because the dataframeeditor is properly used to view multindexes instead of the collection editor as a generic object, avoiding calling the problem method on the item triggering it.

Resolving patch:
diff --git a/spyder/widgets/variableexplorer/collectionseditor.py b/spyder/widgets/variableexplorer/collectionseditor.py
--- a/spyder/widgets/variableexplorer/collectionseditor.py
+++ b/spyder/widgets/variableexplorer/collectionseditor.py
@@ -74,8 +74,14 @@ def __len__(self):
         return len(get_object_attrs(self.__obj__))
 
     def __getitem__(self, key):
-        """Get attribute corresponding to key."""
-        return getattr(self.__obj__, key)
+        """Get the attribute corresponding to given key."""
+        # Fix #6284 where pandas MultiIndex returns NotImplementedError
+        # Due to NA checking not being supported on a multiindex.
+        try:
+            attribute_toreturn = getattr(self.__obj__, key)
+        except NotImplementedError:
+            attribute_toreturn = None
+        return attribute_toreturn
 
     def __setitem__(self, key, value):
         """Set attribute corresponding to key with value."""


Test patch:
diff --git a/spyder/widgets/variableexplorer/tests/test_collectioneditor.py b/spyder/widgets/variableexplorer/tests/test_collectioneditor.py
--- a/spyder/widgets/variableexplorer/tests/test_collectioneditor.py
+++ b/spyder/widgets/variableexplorer/tests/test_collectioneditor.py
@@ -279,5 +279,26 @@ def test_view_module_in_coledit():
     assert editor.widget.editor.readonly
 
 
+def test_notimplementederror_multiindex():
+    """
+    Test that the NotImplementedError when scrolling a MultiIndex is handled.
+
+    Regression test for #6284.
+    """
+    time_deltas = [pandas.Timedelta(minutes=minute)
+                   for minute in range(5, 35, 5)]
+    time_delta_multiindex = pandas.MultiIndex.from_product([[0, 1, 2, 3, 4],
+                                                            time_deltas])
+#    coll = {'rng': rng}
+    col_model = CollectionsModel(None, time_delta_multiindex)
+    assert col_model.rowCount() == col_model.rows_loaded == ROWS_TO_LOAD
+    assert col_model.columnCount() == 4
+    col_model.fetchMore()
+    assert col_model.rowCount() == 2 * ROWS_TO_LOAD
+    for _ in range(3):
+        col_model.fetchMore()
+    assert col_model.rowCount() == 5 * ROWS_TO_LOAD
+
+
 if __name__ == "__main__":
     pytest.main()