Skip to content

Commit 43ed1a9

Browse files
ivirshupmeeseeksmachine
authored andcommitted
Backport PR #55764: REGR: fix return class in _constructor_from_mgr for simple subclasses
1 parent 569f904 commit 43ed1a9

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
@@ -641,7 +641,7 @@ def _constructor(self) -> Callable[..., DataFrame]:
641641
def _constructor_from_mgr(self, mgr, axes):
642642
if self._constructor is DataFrame:
643643
# we are pandas.DataFrame (or a subclass that doesn't override _constructor)
644-
return self._from_mgr(mgr, axes=axes)
644+
return DataFrame._from_mgr(mgr, axes=axes)
645645
else:
646646
assert axes is mgr.axes
647647
return self._constructor(mgr)

pandas/core/series.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ def _constructor(self) -> Callable[..., Series]:
581581
def _constructor_from_mgr(self, mgr, axes):
582582
if self._constructor is Series:
583583
# we are pandas.Series (or a subclass that doesn't override _constructor)
584-
ser = self._from_mgr(mgr, axes=axes)
584+
ser = Series._from_mgr(mgr, axes=axes)
585585
ser._name = None # caller is responsible for setting real name
586586
return ser
587587
else:

pandas/tests/frame/test_subclass.py

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

0 commit comments

Comments
 (0)