Repository: modin-project/modin

Issue:
indexing into an empty dataframe can cause errors

### Describe the problem

We do not properly handle empty DataFrames for some operations. Because we filter out the empty partitions, we can actually end up with an indexing error. Full stack here:

```
Exception                                 Traceback (most recent call last)
~/Downloads/kaggle5/kaggle5.py in <module>
    161         for j in range(0, 3):
    162             try:
--> 163                 guess_df = dataset[(dataset['Sex'] == i) & (dataset['Pclass'] == j+1)]['Age'].dropna()
    164             except:
    165                 print(dataset[(dataset['Sex'] == i) & (dataset['Pclass'] == j+1)])

~/software_builds/modin/modin/pandas/dataframe.py in __getitem__(self, key)
   4504         try:
   4505             if key in self.columns and not is_mi_columns:
-> 4506                 return self._getitem_column(key)
   4507         except (KeyError, ValueError, TypeError):
   4508             pass

~/software_builds/modin/modin/pandas/dataframe.py in _getitem_column(self, key)
   4524     def _getitem_column(self, key):
   4525         return SeriesView(
-> 4526             self._query_compiler.getitem_single_key(key), self, (slice(None), key)
   4527         )
   4528 

~/software_builds/modin/modin/data_management/query_compiler/pandas_query_compiler.py in getitem_single_key(self, key)
   2165             A new PandasDataManager.
   2166         """
-> 2167         new_data = self.getitem_column_array([key])
   2168         if len(self.columns.get_indexer_for([key])) > 1:
   2169             return new_data

~/software_builds/modin/modin/data_management/query_compiler/pandas_query_compiler.py in getitem_column_array(self, key)
   2192 
   2193         result = self.data.apply_func_to_select_indices(
-> 2194             0, getitem, numeric_indices, keep_remaining=False
   2195         )
   2196         # We can't just set the columns to key here because there may be

~/software_builds/modin/modin/engines/base/block_partitions.py in apply_func_to_select_indices(self, axis, func, indices, keep_remaining)
    707             indices = [indices]
    708         partitions_dict = self._get_dict_of_block_index(
--> 709             axis, indices, ordered=not keep_remaining
    710         )
    711         if not axis:

~/software_builds/modin/modin/engines/base/block_partitions.py in _get_dict_of_block_index(self, axis, indices, ordered)
    631         # travel to each partition once.
    632         all_partitions_and_idx = [
--> 633             self._get_blocks_containing_index(axis, i) for i in indices
    634         ]
    635 

~/software_builds/modin/modin/engines/base/block_partitions.py in <listcomp>(.0)
    631         # travel to each partition once.
    632         all_partitions_and_idx = [
--> 633             self._get_blocks_containing_index(axis, i) for i in indices
    634         ]
    635 

~/software_builds/modin/modin/engines/base/block_partitions.py in _get_blocks_containing_index(self, axis, index)
    588         """
    589         if not axis:
--> 590             ErrorMessage.catch_bugs_and_request_email(index > sum(self.block_widths))
    591             cumulative_column_widths = np.array(self.block_widths).cumsum()
    592             block_idx = int(np.digitize(index, cumulative_column_widths))

~/software_builds/modin/modin/error_message.py in catch_bugs_and_request_email(cls, failure_condition)
     25         if failure_condition:
     26             raise Exception(
---> 27                 "Internal Error. "
     28                 "Please email bugs@modin.org with the traceback and command that "
     29                 "caused this error."

Exception: Internal Error. Please email bugs@modin.org with the traceback and command that caused this error.
```
<!-- Describe the problem clearly here. -->

### Source code / logs

`guess_df = dataset[(dataset['Sex'] == i) & (dataset['Pclass'] == j+1)]['Age'].dropna()`
<!-- 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/engines/base/block_partitions.py b/modin/engines/base/block_partitions.py
--- a/modin/engines/base/block_partitions.py
+++ b/modin/engines/base/block_partitions.py
@@ -688,6 +688,8 @@ def apply_func_to_select_indices(self, axis, func, indices, keep_remaining=False
         Returns:
             A new BaseBlockPartitions object, the type of object that called this.
         """
+        if self.partitions.size == 0:
+            return np.array([[]])
         # Handling dictionaries has to be done differently, but we still want
         # to figure out the partitions that need to be applied to, so we will
         # store the dictionary in a separate variable and assign `indices` to
@@ -811,6 +813,8 @@ def apply_func_to_select_indices_along_full_axis(
         Returns:
             A new BaseBlockPartitions object, the type of object that called this.
         """
+        if self.partitions.size == 0:
+            return np.array([[]])
         if isinstance(indices, dict):
             dict_indices = indices
             indices = list(indices.keys())


Test patch: