Repository: modin-project/modin

Issue:
Sometimes df.loc[s] applies to columns instead of rows
<!--
General questions should be asked on the mailing list modin-dev@googlegroups.com.

Before submitting an issue, please fill out the following form.
-->

### Describe the problem
<!-- Describe the problem clearly here. -->
Sometimes df.loc[s] applies to columns instead of rows. This can happen with the label is found in both columns and rows.


### Source code / logs

```python
modin_df = pd.DataFrame(dict(a=[1,2,3],b=[4,5,6],c=[7,8,9]), index=['a','b','c'])
modin_df.loc[['b','a']]
modin_df.loc['b']
```
<!-- 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/pandas/indexing.py b/modin/pandas/indexing.py
--- a/modin/pandas/indexing.py
+++ b/modin/pandas/indexing.py
@@ -90,8 +90,8 @@ def _parse_tuple(tup):
 def _compute_ndim(row_loc, col_loc):
     """Compute the ndim of result from locators
     """
-    row_scaler = is_scalar(row_loc)
-    col_scaler = is_scalar(col_loc)
+    row_scaler = is_scalar(row_loc) or is_tuple(row_loc)
+    col_scaler = is_scalar(col_loc) or is_tuple(col_loc)
 
     if row_scaler and col_scaler:
         ndim = 0
@@ -200,36 +200,20 @@ class _LocIndexer(_LocationIndexerBase):
     """A indexer for ray_df.loc[] functionality"""
 
     def __getitem__(self, key):
-        # When getting along a single axis,
-        if not isinstance(key, tuple):
-            # Try to fasttrack the code through already optimized path
-            try:
-                return self.df.__getitem__(key)
-            # This can happen if it is a list of rows
-            except KeyError:
-                pass
-        else:
-            if len(key) > self.df.ndim:
-                raise IndexingError("Too many indexers")
-            # If we're only slicing columns, handle the case with `__getitem__`
-            if isinstance(key[0], slice) and key[0] == slice(None):
-                if not isinstance(key[1], slice):
-                    # Boolean indexers can just be sliced into the columns object and
-                    # then passed to `__getitem__`
-                    if is_boolean_array(key[1]):
-                        return self.df.__getitem__(self.df.columns[key[1]])
-                    return self.df.__getitem__(key[1])
-                else:
-                    result_slice = self.df.columns.slice_locs(key[1].start, key[1].stop)
-                    return self.df.iloc[:, slice(*result_slice)]
         row_loc, col_loc, ndim, self.row_scaler, self.col_scaler = _parse_tuple(key)
+        if isinstance(row_loc, slice) and row_loc == slice(None):
+            # If we're only slicing columns, handle the case with `__getitem__`
+            if not isinstance(col_loc, slice):
+                # Boolean indexers can just be sliced into the columns object and
+                # then passed to `__getitem__`
+                if is_boolean_array(col_loc):
+                    col_loc = self.df.columns[col_loc]
+                return self.df.__getitem__(col_loc)
+            else:
+                result_slice = self.df.columns.slice_locs(col_loc.start, col_loc.stop)
+                return self.df.iloc[:, slice(*result_slice)]
+
         row_lookup, col_lookup = self._compute_lookup(row_loc, col_loc)
-        # Check that the row_lookup/col_lookup is longer than 1 or that the
-        # row_loc/col_loc is not boolean list to determine the ndim of the
-        # result properly for multiindex.
-        ndim = (0 if len(row_lookup) == 1 and not is_boolean_array(row_loc) else 1) + (
-            0 if len(col_lookup) == 1 and not is_boolean_array(col_loc) else 1
-        )
         result = super(_LocIndexer, self).__getitem__(row_lookup, col_lookup, ndim)
         # Pandas drops the levels that are in the `loc`, so we have to as well.
         if hasattr(result, "index") and isinstance(result.index, pandas.MultiIndex):


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
@@ -544,6 +544,58 @@ def test_equals(self):
 
 
 class TestDataFrameMapMetadata:
+    def test_indexing(self):
+        modin_df = pd.DataFrame(
+            dict(a=[1, 2, 3], b=[4, 5, 6], c=[7, 8, 9]), index=["a", "b", "c"]
+        )
+        pandas_df = pandas.DataFrame(
+            dict(a=[1, 2, 3], b=[4, 5, 6], c=[7, 8, 9]), index=["a", "b", "c"]
+        )
+
+        modin_result = modin_df
+        pandas_result = pandas_df
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df["b"]
+        pandas_result = pandas_df["b"]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df[["b"]]
+        pandas_result = pandas_df[["b"]]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df[["b", "a"]]
+        pandas_result = pandas_df[["b", "a"]]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df.loc["b"]
+        pandas_result = pandas_df.loc["b"]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df.loc[["b"]]
+        pandas_result = pandas_df.loc[["b"]]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df.loc[["b", "a"]]
+        pandas_result = pandas_df.loc[["b", "a"]]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df.loc[["b", "a"], ["a", "c"]]
+        pandas_result = pandas_df.loc[["b", "a"], ["a", "c"]]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df.loc[:, ["a", "c"]]
+        pandas_result = pandas_df.loc[:, ["a", "c"]]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df.loc[:, ["c"]]
+        pandas_result = pandas_df.loc[:, ["c"]]
+        df_equals(modin_result, pandas_result)
+
+        modin_result = modin_df.loc[[]]
+        pandas_result = pandas_df.loc[[]]
+        df_equals(modin_result, pandas_result)
+
     def test_empty_df(self):
         df = pd.DataFrame(index=["a", "b"])
         df_is_empty(df)