Repository: modin-project/modin

Issue:
ignore_index in sort_values has no effect
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**:

Ubuntu 20.04.2 LTS

- **Modin version** (`modin.__version__`):

0.9.1+24.gb7e1188f

- **Python version**:

Python 3.8.6

- **Code we can use to reproduce**:

```python
import modin.pandas as pd

df = pd.DataFrame({"col1": [2, 51, 17], "col2": [5.5, 3.3, 4.4], "col3": ["a", "b", "c"]}, index=["abc", "def", "ghi"])
print(df)
print(df.index)
df.sort_values(by=["col1"], inplace=True, ignore_index=True)
print(df)
```

<!--
You can obtain the Modin version with

python -c "import modin; print(modin.__version__)"
-->

### Describe the problem
<!-- Describe the problem clearly here. -->

With `ignore_index=True` `sort_values` should reset index to default values. But in Modin it doesn't happen.


### 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:

Resolving patch:
diff --git a/modin/backends/pandas/query_compiler.py b/modin/backends/pandas/query_compiler.py
--- a/modin/backends/pandas/query_compiler.py
+++ b/modin/backends/pandas/query_compiler.py
@@ -2958,8 +2958,8 @@ def sort_rows_by_column_values(self, columns, ascending=True, **kwargs):
         PandasQueryCompiler
             A new query compiler that contains result of the sort
         """
-        na_position = kwargs.get("na_position", "last")
-        kind = kwargs.get("kind", "quicksort")
+        ignore_index = kwargs.get("ignore_index", False)
+        kwargs["ignore_index"] = False
         if not is_list_like(columns):
             columns = [columns]
         # Currently, sort_values will just reindex based on the sorted values.
@@ -2969,30 +2969,30 @@ def sort_rows_by_column_values(self, columns, ascending=True, **kwargs):
             col: self.getitem_column_array([col]).to_pandas().squeeze(axis=1)
             for col in columns
         }
+        # Clear index level names because they also appear in broadcast_value_dict
+        orig_index_level_names = self.index.names
+        tmp_index = self.index.copy()
+        tmp_index.names = [None] * tmp_index.nlevels
         # Index may contain duplicates
-        broadcast_values1 = pandas.DataFrame(broadcast_value_dict, index=self.index)
+        broadcast_values1 = pandas.DataFrame(broadcast_value_dict, index=tmp_index)
         # Index without duplicates
         broadcast_values2 = pandas.DataFrame(broadcast_value_dict)
         broadcast_values2 = broadcast_values2.reset_index(drop=True)
         # Index may contain duplicates
         new_index1 = broadcast_values1.sort_values(
-            by=columns,
-            axis=0,
-            ascending=ascending,
-            kind=kind,
-            na_position=na_position,
+            by=columns, axis=0, ascending=ascending, **kwargs
         ).index
         # Index without duplicates
         new_index2 = broadcast_values2.sort_values(
-            by=columns,
-            axis=0,
-            ascending=ascending,
-            kind=kind,
-            na_position=na_position,
+            by=columns, axis=0, ascending=ascending, **kwargs
         ).index
 
         result = self.reset_index(drop=True).reindex(axis=0, labels=new_index2)
-        result.index = new_index1
+        if ignore_index:
+            result = result.reset_index(drop=True)
+        else:
+            result.index = new_index1
+            result.index.names = orig_index_level_names
         return result
 
     def sort_columns_by_row_values(self, rows, ascending=True, **kwargs):
@@ -3010,8 +3010,6 @@ def sort_columns_by_row_values(self, rows, ascending=True, **kwargs):
         PandasQueryCompiler
             A new query compiler that contains result of the sort
         """
-        na_position = kwargs.get("na_position", "last")
-        kind = kwargs.get("kind", "quicksort")
         if not is_list_like(rows):
             rows = [rows]
         ErrorMessage.default_to_pandas("sort_values")
@@ -3024,11 +3022,7 @@ def sort_columns_by_row_values(self, rows, ascending=True, **kwargs):
         )
         broadcast_values.columns = self.columns
         new_columns = broadcast_values.sort_values(
-            by=rows,
-            axis=1,
-            ascending=ascending,
-            kind=kind,
-            na_position=na_position,
+            by=rows, axis=1, ascending=ascending, **kwargs
         ).columns
         return self.reindex(axis=1, labels=new_columns)
 


Test patch:
diff --git a/modin/pandas/test/dataframe/test_join_sort.py b/modin/pandas/test/dataframe/test_join_sort.py
--- a/modin/pandas/test/dataframe/test_join_sort.py
+++ b/modin/pandas/test/dataframe/test_join_sort.py
@@ -22,10 +22,8 @@
     random_state,
     df_equals,
     arg_keys,
-    name_contains,
     test_data_values,
     test_data_keys,
-    numeric_dfs,
     axis_keys,
     axis_values,
     bool_arg_keys,
@@ -33,6 +31,8 @@
     test_data,
     generate_multiindex,
     eval_general,
+    rotate_decimal_digits_or_symbols,
+    extra_test_parameters,
 )
 from modin.config import NPartitions
 
@@ -374,89 +374,127 @@ def test_sort_multiindex(sort_remaining):
 
 
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
+@pytest.mark.parametrize(
+    "by",
+    [
+        pytest.param(
+            "first",
+            marks=pytest.mark.skipif(not extra_test_parameters, reason="extra"),
+        ),
+        pytest.param(
+            "first,last",
+            marks=pytest.mark.skipif(not extra_test_parameters, reason="extra"),
+        ),
+        "first,last,middle",
+        pytest.param(
+            "multiindex_level0",
+            marks=pytest.mark.xfail_backends(
+                ["PandasOnPython", "PandasOnRay", "PandasOnDask"],
+                reason="multiindex levels do not work",
+            ),
+        ),
+        pytest.param(
+            "multiindex_level1,multiindex_level0",
+            marks=pytest.mark.xfail_backends(
+                ["PandasOnPython", "PandasOnRay", "PandasOnDask"],
+                reason="multiindex levels do not work",
+            ),
+        ),
+        pytest.param(
+            "multiindex_level0,last,first,multiindex_level1",
+            marks=pytest.mark.xfail_backends(
+                ["PandasOnPython", "PandasOnRay", "PandasOnDask"],
+                reason="multiindex levels do not work",
+            ),
+        ),
+    ],
+)
 @pytest.mark.parametrize("axis", axis_values, ids=axis_keys)
 @pytest.mark.parametrize(
-    "ascending", bool_arg_values, ids=arg_keys("ascending", bool_arg_keys)
+    "ascending",
+    bool_arg_values + ["list_first_True", "list_first_False"],
+    ids=arg_keys("ascending", bool_arg_keys + ["list_first_True", "list_first_False"]),
+)
+@pytest.mark.parametrize(
+    "inplace", bool_arg_values, ids=arg_keys("inplace", bool_arg_keys)
+)
+@pytest.mark.parametrize(
+    "kind",
+    [
+        pytest.param(
+            "mergesort",
+            marks=pytest.mark.skipif(not extra_test_parameters, reason="extra"),
+        ),
+        "quicksort",
+        pytest.param(
+            "heapsort",
+            marks=pytest.mark.skipif(not extra_test_parameters, reason="extra"),
+        ),
+    ],
 )
 @pytest.mark.parametrize("na_position", ["first", "last"], ids=["first", "last"])
-def test_sort_values(request, data, axis, ascending, na_position):
-    modin_df = pd.DataFrame(data)
-    pandas_df = pandas.DataFrame(data)
-
-    if "empty_data" not in request.node.name and (
-        (axis == 0 or axis == "over rows")
-        or name_contains(request.node.name, numeric_dfs)
-    ):
-        index = modin_df.index if axis == 1 or axis == "columns" else modin_df.columns
-        key = index[0]
-        modin_result = modin_df.sort_values(
-            key,
-            axis=axis,
-            ascending=ascending,
-            na_position=na_position,
-            inplace=False,
-        )
-        pandas_result = pandas_df.sort_values(
-            key,
-            axis=axis,
-            ascending=ascending,
-            na_position=na_position,
-            inplace=False,
-        )
-        df_equals(modin_result, pandas_result)
-
-        modin_df_cp = modin_df.copy()
-        pandas_df_cp = pandas_df.copy()
-        modin_df_cp.sort_values(
-            key,
-            axis=axis,
-            ascending=ascending,
-            na_position=na_position,
-            inplace=True,
-        )
-        pandas_df_cp.sort_values(
-            key,
-            axis=axis,
-            ascending=ascending,
-            na_position=na_position,
-            inplace=True,
-        )
-        df_equals(modin_df_cp, pandas_df_cp)
-
-        keys = [key, index[-1]]
-        modin_result = modin_df.sort_values(
-            keys,
-            axis=axis,
-            ascending=ascending,
-            na_position=na_position,
-            inplace=False,
-        )
-        pandas_result = pandas_df.sort_values(
-            keys,
-            axis=axis,
-            ascending=ascending,
-            na_position=na_position,
-            inplace=False,
-        )
-        df_equals(modin_result, pandas_result)
+@pytest.mark.parametrize(
+    "ignore_index",
+    bool_arg_values,
+    ids=arg_keys("ignore_index", bool_arg_keys),
+)
+@pytest.mark.parametrize("key", [None, rotate_decimal_digits_or_symbols])
+def test_sort_values(
+    data, by, axis, ascending, inplace, kind, na_position, ignore_index, key
+):
+    if (axis == 1 or axis == "columns") and ignore_index:
+        pytest.skip("Pandas bug #39426 which is fixed in Pandas 1.3")
+
+    if ascending is None and key is not None:
+        pytest.skip("Pandas bug #41318")
+
+    if "multiindex" in by:
+        index = generate_multiindex(len(data[list(data.keys())[0]]), nlevels=2)
+        columns = generate_multiindex(len(data.keys()), nlevels=2)
+        data = {columns[ind]: data[key] for ind, key in enumerate(data)}
+    else:
+        index = None
+        columns = None
+
+    modin_df = pd.DataFrame(data, index=index, columns=columns)
+    pandas_df = pandas.DataFrame(data, index=index, columns=columns)
+
+    index = modin_df.index if axis == 1 or axis == "columns" else modin_df.columns
+
+    # Parse "by" spec
+    by_list = []
+    for b in by.split(","):
+        if b == "first":
+            by_list.append(index[0])
+        elif b == "last":
+            by_list.append(index[-1])
+        elif b == "middle":
+            by_list.append(index[len(index) // 2])
+        elif b.startswith("multiindex_level"):
+            by_list.append(index.names[int(b[len("multiindex_level") :])])
+        else:
+            raise Exception('Unknown "by" specifier:' + b)
+
+    # Create "ascending" list
+    if ascending in ["list_first_True", "list_first_False"]:
+        start = 0 if ascending == "list_first_False" else 1
+        ascending = [i & 1 > 0 for i in range(start, len(by_list) + start)]
 
-        modin_df_cp = modin_df.copy()
-        pandas_df_cp = pandas_df.copy()
-        modin_df_cp.sort_values(
-            keys,
-            axis=axis,
-            ascending=ascending,
-            na_position=na_position,
-            inplace=True,
-        )
-        pandas_df_cp.sort_values(
-            keys,
+    eval_general(
+        modin_df,
+        pandas_df,
+        lambda df: df.sort_values(
+            by_list,
             axis=axis,
             ascending=ascending,
+            inplace=inplace,
+            kind=kind,
             na_position=na_position,
-            inplace=True,
-        )
-        df_equals(modin_df_cp, pandas_df_cp)
+            ignore_index=ignore_index,
+            key=key,
+        ),
+        __inplace__=inplace,
+    )
 
 
 def test_sort_values_with_duplicates():
diff --git a/modin/pandas/test/utils.py b/modin/pandas/test/utils.py
--- a/modin/pandas/test/utils.py
+++ b/modin/pandas/test/utils.py
@@ -682,7 +682,7 @@ def execute_callable(fn, inplace=False, md_kwargs={}, pd_kwargs={}):
                     ), f"not acceptable exception type: {md_e.value}"
         else:
             md_result = fn(modin_df, **md_kwargs)
-            return (md_result, pd_result) if not __inplace__ else (modin_df, pandas_df)
+            return (md_result, pd_result) if not inplace else (modin_df, pandas_df)
 
     for key, value in kwargs.items():
         if check_kwargs_callable and callable(value):
@@ -1243,3 +1243,13 @@ def sort_index_for_equal_values(series, ascending=False):
         res.index = res.index.droplevel(0)
     res.name = series.name
     return res
+
+
+def rotate_decimal_digits_or_symbols(value):
+    if value.dtype == object:
+        # When dtype is object, we assume that it is actually strings from MultiIndex level names
+        return [x[-1] + x[:-1] for x in value]
+    else:
+        tens = value // 10
+        ones = value % 10
+        return tens + ones * 10