diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index e56f3ffc01e85..e801b76cdc204 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -656,6 +656,7 @@ Reshaping ^^^^^^^^^ - Bug in :func:`qcut` where values at the quantile boundaries could be incorrectly assigned (:issue:`59355`) - Bug in :meth:`DataFrame.join` inconsistently setting result index name (:issue:`55815`) +- Bug in :meth:`DataFrame.join` when a :class:`DataFrame` with a :class:`MultiIndex` would raise an ``AssertionError`` when :attr:`MultiIndex.names` contained ``None``. (:issue:`58721`) - Bug in :meth:`DataFrame.merge` where merging on a column containing only ``NaN`` values resulted in an out-of-bounds array access (:issue:`59421`) - Bug in :meth:`DataFrame.unstack` producing incorrect results when ``sort=False`` (:issue:`54987`, :issue:`55516`) - Bug in :meth:`DataFrame.unstack` producing incorrect results when manipulating empty :class:`DataFrame` with an :class:`ExtentionDtype` (:issue:`59123`) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index d39c337fbb4b2..c8dbea1fd39ea 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -4516,8 +4516,8 @@ def _join_multi(self, other: Index, how: JoinHow): from pandas.core.reshape.merge import restore_dropped_levels_multijoin # figure out join names - self_names_list = list(com.not_none(*self.names)) - other_names_list = list(com.not_none(*other.names)) + self_names_list = list(self.names) + other_names_list = list(other.names) self_names_order = self_names_list.index other_names_order = other_names_list.index self_names = set(self_names_list) diff --git a/pandas/tests/reshape/merge/test_join.py b/pandas/tests/reshape/merge/test_join.py index f090ded06119a..0f743332acbbe 100644 --- a/pandas/tests/reshape/merge/test_join.py +++ b/pandas/tests/reshape/merge/test_join.py @@ -1098,3 +1098,29 @@ def test_join_multiindex_categorical_output_index_dtype(how, values): result = df1.join(df2, how=how) tm.assert_frame_equal(result, expected) + + +def test_join_multiindex_with_none_as_label(): + # GH 58721 + df1 = DataFrame( + {"A": [1]}, + index=MultiIndex.from_tuples([(3, 3)], names=["X", None]), + ) + df2 = DataFrame( + {"B": [2]}, + index=MultiIndex.from_tuples([(3, 3)], names=[None, "X"]), + ) + + result12 = df1.join(df2) + expected12 = DataFrame( + {"A": [1], "B": [2]}, + index=MultiIndex.from_tuples([(3, 3)], names=["X", None]), + ) + tm.assert_frame_equal(result12, expected12) + + result21 = df2.join(df1) + expected21 = DataFrame( + {"B": [2], "A": [1]}, + index=MultiIndex.from_tuples([(3, 3)], names=[None, "X"]), + ) + tm.assert_frame_equal(result21, expected21)