Skip to content

Commit f5bb775

Browse files
authored
REGR: Index.join raising TypeError when joining an empty index to a mixed type index (#57101)
* fix regression in join with empty * mypy * move empty check
1 parent 42e4e4c commit f5bb775

File tree

3 files changed

+53
-32
lines changed

3 files changed

+53
-32
lines changed

doc/source/whatsnew/v2.2.1.rst

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Fixed regressions
1919
- Fixed regression in :func:`wide_to_long` raising an ``AttributeError`` for string columns (:issue:`57066`)
2020
- Fixed regression in :meth:`DataFrameGroupBy.idxmin`, :meth:`DataFrameGroupBy.idxmax`, :meth:`SeriesGroupBy.idxmin`, :meth:`SeriesGroupBy.idxmax` ignoring the ``skipna`` argument (:issue:`57040`)
2121
- Fixed regression in :meth:`DataFrameGroupBy.idxmin`, :meth:`DataFrameGroupBy.idxmax`, :meth:`SeriesGroupBy.idxmin`, :meth:`SeriesGroupBy.idxmax` where values containing the minimum or maximum value for the dtype could produce incorrect results (:issue:`57040`)
22+
- Fixed regression in :meth:`Index.join` raising ``TypeError`` when joining an empty index to a non-empty index containing mixed dtype values (:issue:`57048`)
2223
- Fixed regression in :meth:`Series.pct_change` raising a ``ValueError`` for an empty :class:`Series` (:issue:`57056`)
2324

2425
.. ---------------------------------------------------------------------------

pandas/core/indexes/base.py

+33-32
Original file line numberDiff line numberDiff line change
@@ -4613,38 +4613,12 @@ def join(
46134613
if level is not None and (self._is_multi or other._is_multi):
46144614
return self._join_level(other, level, how=how)
46154615

4616-
lidx: np.ndarray | None
4617-
ridx: np.ndarray | None
4618-
4619-
if len(other) == 0:
4620-
if how in ("left", "outer"):
4621-
if sort and not self.is_monotonic_increasing:
4622-
lidx = self.argsort()
4623-
join_index = self.take(lidx)
4624-
else:
4625-
lidx = None
4626-
join_index = self._view()
4627-
ridx = np.broadcast_to(np.intp(-1), len(join_index))
4628-
return join_index, lidx, ridx
4629-
elif how in ("right", "inner", "cross"):
4630-
join_index = other._view()
4631-
lidx = np.array([], dtype=np.intp)
4632-
return join_index, lidx, None
4633-
4634-
if len(self) == 0:
4635-
if how in ("right", "outer"):
4636-
if sort and not other.is_monotonic_increasing:
4637-
ridx = other.argsort()
4638-
join_index = other.take(ridx)
4639-
else:
4640-
ridx = None
4641-
join_index = other._view()
4642-
lidx = np.broadcast_to(np.intp(-1), len(join_index))
4643-
return join_index, lidx, ridx
4644-
elif how in ("left", "inner", "cross"):
4645-
join_index = self._view()
4646-
ridx = np.array([], dtype=np.intp)
4647-
return join_index, None, ridx
4616+
if len(self) == 0 or len(other) == 0:
4617+
try:
4618+
return self._join_empty(other, how, sort)
4619+
except TypeError:
4620+
# object dtype; non-comparable objects
4621+
pass
46484622

46494623
if self.dtype != other.dtype:
46504624
dtype = self._find_common_type_compat(other)
@@ -4679,6 +4653,33 @@ def join(
46794653

46804654
return self._join_via_get_indexer(other, how, sort)
46814655

4656+
@final
4657+
def _join_empty(
4658+
self, other: Index, how: JoinHow, sort: bool
4659+
) -> tuple[Index, npt.NDArray[np.intp] | None, npt.NDArray[np.intp] | None]:
4660+
assert len(self) == 0 or len(other) == 0
4661+
_validate_join_method(how)
4662+
4663+
lidx: np.ndarray | None
4664+
ridx: np.ndarray | None
4665+
4666+
if len(other):
4667+
how = cast(JoinHow, {"left": "right", "right": "left"}.get(how, how))
4668+
join_index, ridx, lidx = other._join_empty(self, how, sort)
4669+
elif how in ["left", "outer"]:
4670+
if sort and not self.is_monotonic_increasing:
4671+
lidx = self.argsort()
4672+
join_index = self.take(lidx)
4673+
else:
4674+
lidx = None
4675+
join_index = self._view()
4676+
ridx = np.broadcast_to(np.intp(-1), len(join_index))
4677+
else:
4678+
join_index = other._view()
4679+
lidx = np.array([], dtype=np.intp)
4680+
ridx = None
4681+
return join_index, lidx, ridx
4682+
46824683
@final
46834684
def _join_via_get_indexer(
46844685
self, other: Index, how: JoinHow, sort: bool

pandas/tests/reshape/merge/test_join.py

+19
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,25 @@ def test_join_empty(left_empty, how, exp):
10411041
tm.assert_frame_equal(result, expected)
10421042

10431043

1044+
def test_join_empty_uncomparable_columns():
1045+
# GH 57048
1046+
df1 = DataFrame()
1047+
df2 = DataFrame(columns=["test"])
1048+
df3 = DataFrame(columns=["foo", ("bar", "baz")])
1049+
1050+
result = df1 + df2
1051+
expected = DataFrame(columns=["test"])
1052+
tm.assert_frame_equal(result, expected)
1053+
1054+
result = df2 + df3
1055+
expected = DataFrame(columns=[("bar", "baz"), "foo", "test"])
1056+
tm.assert_frame_equal(result, expected)
1057+
1058+
result = df1 + df3
1059+
expected = DataFrame(columns=[("bar", "baz"), "foo"])
1060+
tm.assert_frame_equal(result, expected)
1061+
1062+
10441063
@pytest.mark.parametrize(
10451064
"how, values",
10461065
[

0 commit comments

Comments
 (0)