Skip to content

Commit 95561fc

Browse files
REGR: fix return class in _constructor_from_mgr for simple subclasses (pandas-dev#55764)
Co-authored-by: Joris Van den Bossche <[email protected]>
1 parent 775f716 commit 95561fc

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

doc/source/whatsnew/v2.1.3.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ including other versions of pandas.
1313

1414
Fixed regressions
1515
~~~~~~~~~~~~~~~~~
16-
-
16+
- Fixed infinite recursion from operations that return a new object on some DataFrame subclasses (:issue:`55763`)
1717
-
1818

1919
.. ---------------------------------------------------------------------------

pandas/core/frame.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ def _constructor(self) -> Callable[..., DataFrame]:
648648
def _constructor_from_mgr(self, mgr, axes):
649649
if self._constructor is DataFrame:
650650
# we are pandas.DataFrame (or a subclass that doesn't override _constructor)
651-
return self._from_mgr(mgr, axes=axes)
651+
return DataFrame._from_mgr(mgr, axes=axes)
652652
else:
653653
assert axes is mgr.axes
654654
return self._constructor(mgr)

pandas/core/series.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ def _constructor(self) -> Callable[..., Series]:
637637
def _constructor_from_mgr(self, mgr, axes):
638638
if self._constructor is Series:
639639
# we are pandas.Series (or a subclass that doesn't override _constructor)
640-
ser = self._from_mgr(mgr, axes=axes)
640+
ser = Series._from_mgr(mgr, axes=axes)
641641
ser._name = None # caller is responsible for setting real name
642642
return ser
643643
else:

pandas/tests/frame/test_subclass.py

+41
Original file line numberDiff line numberDiff line change
@@ -773,3 +773,44 @@ def test_constructor_with_metadata():
773773
)
774774
subset = df[["A", "B"]]
775775
assert isinstance(subset, MySubclassWithMetadata)
776+
777+
778+
class SimpleDataFrameSubClass(DataFrame):
779+
"""A subclass of DataFrame that does not define a constructor."""
780+
781+
782+
class SimpleSeriesSubClass(Series):
783+
"""A subclass of Series that does not define a constructor."""
784+
785+
786+
class TestSubclassWithoutConstructor:
787+
def test_copy_df(self):
788+
expected = DataFrame({"a": [1, 2, 3]})
789+
result = SimpleDataFrameSubClass(expected).copy()
790+
791+
assert (
792+
type(result) is DataFrame
793+
) # assert_frame_equal only checks isinstance(lhs, type(rhs))
794+
tm.assert_frame_equal(result, expected)
795+
796+
def test_copy_series(self):
797+
expected = Series([1, 2, 3])
798+
result = SimpleSeriesSubClass(expected).copy()
799+
800+
tm.assert_series_equal(result, expected)
801+
802+
def test_series_to_frame(self):
803+
orig = Series([1, 2, 3])
804+
expected = orig.to_frame()
805+
result = SimpleSeriesSubClass(orig).to_frame()
806+
807+
assert (
808+
type(result) is DataFrame
809+
) # assert_frame_equal only checks isinstance(lhs, type(rhs))
810+
tm.assert_frame_equal(result, expected)
811+
812+
def test_groupby(self):
813+
df = SimpleDataFrameSubClass(DataFrame({"a": [1, 2, 3]}))
814+
815+
for _, v in df.groupby("a"):
816+
assert type(v) is DataFrame

0 commit comments

Comments
 (0)