diff --git a/python/pyarrow/pandas_compat.py b/python/pyarrow/pandas_compat.py index 495df5645f3..4ff587b702b 100644 --- a/python/pyarrow/pandas_compat.py +++ b/python/pyarrow/pandas_compat.py @@ -547,8 +547,12 @@ def _get_range_index_descriptor(level): def _get_index_level_values(index): - n = len(getattr(index, 'levels', [index])) - return [index.get_level_values(i) for i in range(n)] + if not hasattr(index, 'levels'): + return [index.get_level_values(0)] + # get_level_values() matches integers against level names first + positional = index.set_names(list(range(index.nlevels))) + return [positional.get_level_values(i).rename(name) + for i, name in enumerate(index.names)] def _resolve_columns_of_interest(df, schema, columns): diff --git a/python/pyarrow/tests/test_pandas.py b/python/pyarrow/tests/test_pandas.py index 2391cb26000..1f09a9247e6 100644 --- a/python/pyarrow/tests/test_pandas.py +++ b/python/pyarrow/tests/test_pandas.py @@ -5370,3 +5370,23 @@ def test_pandas_array_likes_with_extension_arrays(): for box in [pd.array, pd.Index, pd.Series]: _check_array_roundtrip(box(arr[0]), expected=pd.Series( arr[1]) if arr[1] is not None else None) + + +def test_multiindex_integer_level_names(): + # https://github.com/apache/arrow/issues/38983 + index = pd.MultiIndex.from_tuples( + [(10, 20), (30, 40), (50, 60), (70, 80)], names=[1, 2]) + df = pd.DataFrame({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]}, index=index) + + # non-str index names are converted to str, with a warning + with pytest.warns(UserWarning): + table = pa.Table.from_pandas(df) + + assert table.column_names == ["a", "b", "1", "2"] + assert table.column(2).to_pylist() == [10, 30, 50, 70] + assert table.column(3).to_pylist() == [20, 40, 60, 80] + + expected = df.copy() + expected.index.names = ["1", "2"] + with pytest.warns(UserWarning): + _check_pandas_roundtrip(df, expected=expected, preserve_index=True)