Repository: modin-project/modin

Issue:
read_excel error "Internal and external indices on axis 1 do not match." When multiple empty columns on first line
This error comes from a mismatch in Modin pandas behavior when naming columns. The pandas naming convention is not completely consistent so further investigation is required.

Error stacktrace:
```
>>> pd.read_excel('test_emptyline.xlsx')
UserWarning: Parallel `read_excel` is a new feature! Please email bug_reports@modin.org if you run into any problems.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\foo\modin\pandas\dataframe.py", line 183, in __repr__
    result = repr(self._build_repr_df(num_rows, num_cols))
  File "c:\foo\modin\pandas\base.py", line 168, in _build_repr_df
    return self.iloc[indexer]._query_compiler.to_pandas()
  File "c:\foo\modin\backends\pandas\query_compiler.py", line 233, in to_pandas
    return self._modin_frame.to_pandas()
  File "c:\foo\modin\engines\base\frame\data.py", line 2063, in to_pandas
    f"Internal and external indices on axis {axis} do not match.",
  File "c:\foo\modin\error_message.py", line 63, in catch_bugs_and_request_email
    " caused this error.\n{}".format(extra_log)
Exception: Internal Error. Please email bug_reports@modin.org with the traceback and command that caused this error.
Internal and external indices on axis 1 do not match.
```


Discussion:
As a temporary workaround, setting `df.columns = df.columns` fixes the mismatch, but the columns will not be `"Unnamed X"`. In the case these names are thrown away later it will not matter.
@devin-petersohn do you have a reproducer or at least a sample? It's unclear to me how to reproduce the issue.
This should be able to be reproduced with an excel file with a blank first line.
Yeah, got that showing up using a cooked-up excel file. Thanks!
Note: this happens only with "parallel Excel reader" (i.e. with `MODIN_ENGINE` != `Python`).

Resolving patch:
diff --git a/modin/engines/base/io/text/excel_dispatcher.py b/modin/engines/base/io/text/excel_dispatcher.py
--- a/modin/engines/base/io/text/excel_dispatcher.py
+++ b/modin/engines/base/io/text/excel_dispatcher.py
@@ -76,6 +76,7 @@ def _read(cls, io, **kwargs):
                 # close only if it were us who opened the object
                 io_file.close()
 
+        pandas_kw = dict(kwargs)  # preserve original kwargs
         with ZipFile(io) as z:
             from io import BytesIO
 
@@ -129,6 +130,13 @@ def _read(cls, io, **kwargs):
             # Remove column names that are specified as `index_col`
             if index_col is not None:
                 column_names = column_names.drop(column_names[index_col])
+
+            if not all(column_names):
+                # some column names are empty, use pandas reader to take the names from it
+                pandas_kw["nrows"] = 1
+                df = pandas.read_excel(io, **pandas_kw)
+                column_names = df.columns
+
             # Compute partition metadata upfront so it is uniform for all partitions
             chunk_size = max(1, (total_bytes - f.tell()) // num_partitions)
             num_splits = min(len(column_names), num_partitions)


Test patch:
diff --git a/modin/pandas/test/data/test_emptyline.xlsx b/modin/pandas/test/data/test_emptyline.xlsx
new file mode 100644
Binary files /dev/null and b/modin/pandas/test/data/test_emptyline.xlsx differ
diff --git a/modin/pandas/test/test_io.py b/modin/pandas/test/test_io.py
--- a/modin/pandas/test/test_io.py
+++ b/modin/pandas/test/test_io.py
@@ -1325,6 +1325,13 @@ def test_from_excel_sheetname_title():
     df_equals(modin_df, pandas_df)
 
 
+@check_file_leaks
+def test_excel_empty_line():
+    path = "modin/pandas/test/data/test_emptyline.xlsx"
+    modin_df = pd.read_excel(path)
+    assert str(modin_df)
+
+
 @pytest.mark.parametrize(
     "sheet_name",
     ["Sheet1", "AnotherSpecialName", "SpecialName", "SecondSpecialName", 0, 1, 2, 3],