Skip to content

Commit

Permalink
Backport PR pandas-dev#57101 on branch 2.2.x (REGR: Index.join raisin…
Browse files Browse the repository at this point in the history
…g TypeError when joining an empty index to a mixed type index) (pandas-dev#57133)

Backport PR pandas-dev#57101: REGR: Index.join raising TypeError when joining an empty index to a mixed type index

Co-authored-by: Luke Manley <lukemanley@gmail.com>
  • Loading branch information
meeseeksmachine and lukemanley committed Jan 29, 2024
1 parent df0762d commit c1723cd
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 32 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.2.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Fixed regressions
- Fixed regression in :func:`wide_to_long` raising an ``AttributeError`` for string columns (:issue:`57066`)
- Fixed regression in :meth:`DataFrameGroupBy.idxmin`, :meth:`DataFrameGroupBy.idxmax`, :meth:`SeriesGroupBy.idxmin`, :meth:`SeriesGroupBy.idxmax` ignoring the ``skipna`` argument (:issue:`57040`)
- 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`)
- Fixed regression in :meth:`Index.join` raising ``TypeError`` when joining an empty index to a non-empty index containing mixed dtype values (:issue:`57048`)
- Fixed regression in :meth:`Series.pct_change` raising a ``ValueError`` for an empty :class:`Series` (:issue:`57056`)

.. ---------------------------------------------------------------------------
Expand Down
65 changes: 33 additions & 32 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4615,38 +4615,12 @@ def join(
if level is not None and (self._is_multi or other._is_multi):
return self._join_level(other, level, how=how)

lidx: np.ndarray | None
ridx: np.ndarray | None

if len(other) == 0:
if how in ("left", "outer"):
if sort and not self.is_monotonic_increasing:
lidx = self.argsort()
join_index = self.take(lidx)
else:
lidx = None
join_index = self._view()
ridx = np.broadcast_to(np.intp(-1), len(join_index))
return join_index, lidx, ridx
elif how in ("right", "inner", "cross"):
join_index = other._view()
lidx = np.array([], dtype=np.intp)
return join_index, lidx, None

if len(self) == 0:
if how in ("right", "outer"):
if sort and not other.is_monotonic_increasing:
ridx = other.argsort()
join_index = other.take(ridx)
else:
ridx = None
join_index = other._view()
lidx = np.broadcast_to(np.intp(-1), len(join_index))
return join_index, lidx, ridx
elif how in ("left", "inner", "cross"):
join_index = self._view()
ridx = np.array([], dtype=np.intp)
return join_index, None, ridx
if len(self) == 0 or len(other) == 0:
try:
return self._join_empty(other, how, sort)
except TypeError:
# object dtype; non-comparable objects
pass

if self.dtype != other.dtype:
dtype = self._find_common_type_compat(other)
Expand Down Expand Up @@ -4681,6 +4655,33 @@ def join(

return self._join_via_get_indexer(other, how, sort)

@final
def _join_empty(
self, other: Index, how: JoinHow, sort: bool
) -> tuple[Index, npt.NDArray[np.intp] | None, npt.NDArray[np.intp] | None]:
assert len(self) == 0 or len(other) == 0
_validate_join_method(how)

lidx: np.ndarray | None
ridx: np.ndarray | None

if len(other):
how = cast(JoinHow, {"left": "right", "right": "left"}.get(how, how))
join_index, ridx, lidx = other._join_empty(self, how, sort)
elif how in ["left", "outer"]:
if sort and not self.is_monotonic_increasing:
lidx = self.argsort()
join_index = self.take(lidx)
else:
lidx = None
join_index = self._view()
ridx = np.broadcast_to(np.intp(-1), len(join_index))
else:
join_index = other._view()
lidx = np.array([], dtype=np.intp)
ridx = None
return join_index, lidx, ridx

@final
def _join_via_get_indexer(
self, other: Index, how: JoinHow, sort: bool
Expand Down
19 changes: 19 additions & 0 deletions pandas/tests/reshape/merge/test_join.py
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,25 @@ def test_join_empty(left_empty, how, exp):
tm.assert_frame_equal(result, expected)


def test_join_empty_uncomparable_columns():
# GH 57048
df1 = DataFrame()
df2 = DataFrame(columns=["test"])
df3 = DataFrame(columns=["foo", ("bar", "baz")])

result = df1 + df2
expected = DataFrame(columns=["test"])
tm.assert_frame_equal(result, expected)

result = df2 + df3
expected = DataFrame(columns=[("bar", "baz"), "foo", "test"])
tm.assert_frame_equal(result, expected)

result = df1 + df3
expected = DataFrame(columns=[("bar", "baz"), "foo"])
tm.assert_frame_equal(result, expected)


@pytest.mark.parametrize(
"how, values",
[
Expand Down

0 comments on commit c1723cd

Please sign in to comment.