Repository: modin-project/modin

Issue:
BUG: `.index` attribute extraction of an empty frame returns a list instead of a `pandas.Index`
### Modin version checks

- [X] I have checked that this issue has not already been reported.

- [X] I have confirmed this bug exists on the latest released version of Modin.

- [X] I have confirmed this bug exists on the main branch of Modin. (In order to do this you can follow [this guide](https://modin.readthedocs.io/en/stable/getting_started/installation.html#installing-from-the-github-master-branch).)


### Reproducible Example

```python
import modin.pandas as pd

empty_frame = pd.DataFrame({"a": [1, 2]}).query("a > 100")
index = empty_frame.index

print(index) # []
print(type(index)) # <class 'list'>
print(index.name) # AttributeError
```


### Issue Description

This happens because the logic that computes indices unconditionally filters out empty ones, thus returning an empty list instead of an index in case all of the partitions returned a zero-length index.
    https://github.com/modin-project/modin/blob/4114183f84d3d152126510655db5698fd4ea1071/modin/core/dataframe/pandas/partitioning/partition_manager.py#L883-L888

### Expected Behavior

Return an empty `pandas.Index` instead of a list

### Error Logs

<details>

```python-traceback

Replace this line with the error backtrace (if applicable).

```

</details>


### Installed Versions

<details>

Replace this line with the output of pd.show_versions()

</details>



Discussion:

Resolving patch:
diff --git a/modin/core/dataframe/pandas/partitioning/partition_manager.py b/modin/core/dataframe/pandas/partitioning/partition_manager.py
--- a/modin/core/dataframe/pandas/partitioning/partition_manager.py
+++ b/modin/core/dataframe/pandas/partitioning/partition_manager.py
@@ -878,13 +878,22 @@ def get_indices(cls, axis, partitions, index_func=None):
         ErrorMessage.catch_bugs_and_request_email(not callable(index_func))
         func = cls.preprocess_func(index_func)
         target = partitions.T if axis == 0 else partitions
-        new_idx = [idx.apply(func) for idx in target[0]] if len(target) else []
-        new_idx = cls.get_objects_from_partitions(new_idx)
-        # filter empty indexes
+        if len(target):
+            new_idx = [idx.apply(func) for idx in target[0]]
+            new_idx = cls.get_objects_from_partitions(new_idx)
+        else:
+            new_idx = [pandas.Index([])]
+
+        # filter empty indexes in case there are multiple partitions
         total_idx = list(filter(len, new_idx))
         if len(total_idx) > 0:
             # TODO FIX INFORMATION LEAK!!!!1!!1!!
             total_idx = total_idx[0].append(total_idx[1:])
+        else:
+            # Meaning that all partitions returned a zero-length index,
+            # in this case, we return an index of any partition to preserve
+            # the index's metadata
+            total_idx = new_idx[0]
         return total_idx, new_idx
 
     @classmethod


Test patch:
diff --git a/modin/pandas/test/dataframe/test_indexing.py b/modin/pandas/test/dataframe/test_indexing.py
--- a/modin/pandas/test/dataframe/test_indexing.py
+++ b/modin/pandas/test/dataframe/test_indexing.py
@@ -2262,3 +2262,24 @@ def func(df):
         return df_copy
 
     eval_general(modin_df, pandas_df, func)
+
+
+def test_index_of_empty_frame():
+    # Test on an empty frame created by user
+    md_df, pd_df = create_test_dfs(
+        {}, index=pandas.Index([], name="index name"), columns=["a", "b"]
+    )
+    assert md_df.empty and pd_df.empty
+    df_equals(md_df.index, pd_df.index)
+
+    # Test on an empty frame produced by Modin's logic
+    data = test_data_values[0]
+    md_df, pd_df = create_test_dfs(
+        data, index=pandas.RangeIndex(len(next(iter(data.values()))), name="index name")
+    )
+
+    md_res = md_df.query(f"{md_df.columns[0]} > {RAND_HIGH}")
+    pd_res = pd_df.query(f"{pd_df.columns[0]} > {RAND_HIGH}")
+
+    assert md_res.empty and pd_res.empty
+    df_equals(md_res.index, pd_res.index)