Repository: modin-project/modin

Issue:
sort_index does not work with MultiIndex
<!--
General questions should be asked on the mailing list modin-dev@googlegroups.com.

Before submitting an issue, please fill out the following form.
-->

### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: macOS 10.14.5 (18F132)
- **Modin installed from (source or binary)**: `pip install modin`
- **Modin version**:0.5.3
- **Python version**:3.7.3
- **Exact command to reproduce**:
       
      import modin.pandas as pd
  
      df = pd.DataFrame([['one', 'A', 100], ['two', 'A', 101], ['three', 'A', 102],
                         ['one', 'B', 103], ['two', 'B', 104], ['three', 'B', 105]],
                        columns=['c1', 'c2', 'c3'])
  
      df.set_index(['c1', 'c2']).sort_index()
<!--
You can obtain the Modin version with

python -c "import modin; print(modin.__version__)"
-->

### Describe the problem
<!-- Describe the problem clearly here. -->

Sorting index of a MultiIndex causes error:

    NotImplementedError                       Traceback (most recent call last)
    <ipython-input-7-06ffb9961dfc> in <module>
    ----> 1 hh.sort_index(axis=0)

    ~/.pyenv/versions/3.7.3/envs/env/lib/python3.7/site-packages/modin/pandas/base.py in sort_index(self, axis, level, ascending, inplace, kind, na_position, sort_remaining, by)
       2570             return self.sort_values(by, axis=axis, ascending=ascending, inplace=inplace)
       2571         new_query_compiler = self._query_compiler.sort_index(
    -> 2572             axis=axis, ascending=ascending, kind=kind, na_position=na_position
       2573         )
       2574         if inplace:

    ~/.pyenv/versions/3.7.3/envs/env/lib/python3.7/site-packages/modin/backends/pandas/query_compiler.py in sort_index(self, **kwargs)
       1762             new_index = self.index
       1763         else:
    -> 1764             new_index = pandas.Series(self.index).sort_values(**kwargs)
       1765             new_columns = self.columns
       1766         return self.__constructor__(

    ~/.pyenv/versions/3.7.3/envs/env/lib/python3.7/site-packages/pandas/core/series.py in __init__(self, data, index, dtype, name, copy, fastpath)
        175
        176             if isinstance(data, MultiIndex):
    --> 177                 raise NotImplementedError("initializing a Series from a "
        178                                           "MultiIndex is not supported")
        179             elif isinstance(data, Index):

    NotImplementedError: initializing a Series from a MultiIndex is not supported

However, the original `pandas` works well. Also, passing `level` to the function caused another error

    AssertionError                            Traceback (most recent call last)
    <ipython-input-1-75aa63e76c3d> in <module>
          5                   columns=['c1', 'c2', 'c3'])
          6
    ----> 7 df.set_index(['c1', 'c2']).sort_index(level=0)

    ~/.pyenv/versions/3.7.3/envs/env/lib/python3.7/site-packages/modin/pandas/base.py in sort_index(self, axis, level, ascending, inplace, kind, na_position, sort_remaining, by)
       2558                 sort_remaining=sort_remaining,
       2559             )
    -> 2560             return self._create_or_update_from_compiler(new_query_compiler, inplace)
       2561         if by is not None:
       2562             warnings.warn(

    ~/.pyenv/versions/3.7.3/envs/env/lib/python3.7/site-packages/modin/pandas/dataframe.py in _create_or_update_from_compiler(self, new_query_compiler, inplace)
       2105             isinstance(new_query_compiler, type(self._query_compiler))
       2106             or type(new_query_compiler) in self._query_compiler.__class__.__bases__
    -> 2107         ), "Invalid Query Compiler object: {}".format(type(new_query_compiler))
       2108         if not inplace:
       2109             return DataFrame(query_compiler=new_query_compiler)

    AssertionError: Invalid Query Compiler object: <class 'modin.pandas.dataframe.DataFrame'>

### Source code / logs
<!-- Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached. Try to provide a reproducible test case that is the bare minimum necessary to generate the problem. -->


Discussion:
Hi @Yevgnen thanks for the report!

This is a bug and we will fix it for the next release. We are defaulting to pandas for MultiIndex in a lot of operations, including sort, but in this case we did not convert it back to a Modin DataFrame after the operation. Thanks again for the report!

Resolving patch:
diff --git a/modin/pandas/base.py b/modin/pandas/base.py
--- a/modin/pandas/base.py
+++ b/modin/pandas/base.py
@@ -2546,7 +2546,10 @@ def sort_index(
             A sorted DataFrame
         """
         axis = self._get_axis_number(axis)
-        if level is not None:
+        if level is not None or (
+            (axis == 0 and isinstance(self.index, pandas.MultiIndex))
+            or (axis == 1 and isinstance(self.columns, pandas.MultiIndex))
+        ):
             new_query_compiler = self._default_to_pandas(
                 "sort_index",
                 axis=axis,
@@ -2556,7 +2559,7 @@ def sort_index(
                 kind=kind,
                 na_position=na_position,
                 sort_remaining=sort_remaining,
-            )
+            )._query_compiler
             return self._create_or_update_from_compiler(new_query_compiler, inplace)
         if by is not None:
             warnings.warn(


Test patch:
diff --git a/modin/pandas/test/test_dataframe.py b/modin/pandas/test/test_dataframe.py
--- a/modin/pandas/test/test_dataframe.py
+++ b/modin/pandas/test/test_dataframe.py
@@ -4257,6 +4257,21 @@ def test_sort_index(self, data, axis, ascending, na_position, sort_remaining):
         )
         df_equals(modin_df_cp, pandas_df_cp)
 
+        # MultiIndex
+        modin_df = pd.DataFrame(data)
+        pandas_df = pandas.DataFrame(data)
+        modin_df.index = pd.MultiIndex.from_tuples(
+            [(i // 10, i // 5, i) for i in range(len(modin_df))]
+        )
+        pandas_df.index = pandas.MultiIndex.from_tuples(
+            [(i // 10, i // 5, i) for i in range(len(pandas_df))]
+        )
+
+        with pytest.warns(UserWarning):
+            df_equals(modin_df.sort_index(level=0), pandas_df.sort_index(level=0))
+        with pytest.warns(UserWarning):
+            df_equals(modin_df.sort_index(axis=0), pandas_df.sort_index(axis=0))
+
     @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
     @pytest.mark.parametrize("axis", axis_values, ids=axis_keys)
     @pytest.mark.parametrize(