Skip to content

Commit

Permalink
REGR: fix return class in _constructor_from_mgr for simple subclasses (
Browse files Browse the repository at this point in the history
…#55764)

Co-authored-by: Joris Van den Bossche <jorisvandenbossche@gmail.com>
  • Loading branch information
ivirshup and jorisvandenbossche committed Nov 9, 2023
1 parent 775f716 commit 95561fc
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 3 deletions.
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v2.1.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ including other versions of pandas.

Fixed regressions
~~~~~~~~~~~~~~~~~
-
- Fixed infinite recursion from operations that return a new object on some DataFrame subclasses (:issue:`55763`)
-

.. ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ def _constructor(self) -> Callable[..., DataFrame]:
def _constructor_from_mgr(self, mgr, axes):
if self._constructor is DataFrame:
# we are pandas.DataFrame (or a subclass that doesn't override _constructor)
return self._from_mgr(mgr, axes=axes)
return DataFrame._from_mgr(mgr, axes=axes)
else:
assert axes is mgr.axes
return self._constructor(mgr)
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ def _constructor(self) -> Callable[..., Series]:
def _constructor_from_mgr(self, mgr, axes):
if self._constructor is Series:
# we are pandas.Series (or a subclass that doesn't override _constructor)
ser = self._from_mgr(mgr, axes=axes)
ser = Series._from_mgr(mgr, axes=axes)
ser._name = None # caller is responsible for setting real name
return ser
else:
Expand Down
41 changes: 41 additions & 0 deletions pandas/tests/frame/test_subclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,3 +773,44 @@ def test_constructor_with_metadata():
)
subset = df[["A", "B"]]
assert isinstance(subset, MySubclassWithMetadata)


class SimpleDataFrameSubClass(DataFrame):
"""A subclass of DataFrame that does not define a constructor."""


class SimpleSeriesSubClass(Series):
"""A subclass of Series that does not define a constructor."""


class TestSubclassWithoutConstructor:
def test_copy_df(self):
expected = DataFrame({"a": [1, 2, 3]})
result = SimpleDataFrameSubClass(expected).copy()

assert (
type(result) is DataFrame
) # assert_frame_equal only checks isinstance(lhs, type(rhs))
tm.assert_frame_equal(result, expected)

def test_copy_series(self):
expected = Series([1, 2, 3])
result = SimpleSeriesSubClass(expected).copy()

tm.assert_series_equal(result, expected)

def test_series_to_frame(self):
orig = Series([1, 2, 3])
expected = orig.to_frame()
result = SimpleSeriesSubClass(orig).to_frame()

assert (
type(result) is DataFrame
) # assert_frame_equal only checks isinstance(lhs, type(rhs))
tm.assert_frame_equal(result, expected)

def test_groupby(self):
df = SimpleDataFrameSubClass(DataFrame({"a": [1, 2, 3]}))

for _, v in df.groupby("a"):
assert type(v) is DataFrame

0 comments on commit 95561fc

Please sign in to comment.