Skip to content

Commit 59b49e1

Browse files
committed
Remove NDFrame.__constructor_expanddim
1 parent 940c325 commit 59b49e1

File tree

6 files changed

+15
-35
lines changed

6 files changed

+15
-35
lines changed

doc/source/development/extending.rst

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -329,21 +329,11 @@ Each data structure has several *constructor properties* for returning a new
329329
data structure as the result of an operation. By overriding these properties,
330330
you can retain subclasses through ``pandas`` data manipulations.
331331

332-
There are 3 constructor properties to be defined:
332+
There are 3 possible constructor properties to be defined on a subclass:
333333

334-
* ``_constructor``: Used when a manipulation result has the same dimensions as the original.
335-
* ``_constructor_sliced``: Used when a manipulation result has one lower dimension(s) as the original, such as ``DataFrame`` single columns slicing.
336-
* ``_constructor_expanddim``: Used when a manipulation result has one higher dimension as the original, such as ``Series.to_frame()``.
337-
338-
Following table shows how ``pandas`` data structures define constructor properties by default.
339-
340-
=========================== ======================= =============
341-
Property Attributes ``Series`` ``DataFrame``
342-
=========================== ======================= =============
343-
``_constructor`` ``Series`` ``DataFrame``
344-
``_constructor_sliced`` ``NotImplementedError`` ``Series``
345-
``_constructor_expanddim`` ``DataFrame`` ``NotImplementedError``
346-
=========================== ======================= =============
334+
* ``DataFrame/Series._constructor``: Used when a manipulation result has the same (sub-)class as the original.
335+
* ``DataFrame._constructor_sliced``: Used when a ``DataFrame`` (sub-)class manipulation result should be a ``Series`` (sub-)class.
336+
* ``Series._constructor_expanddim``: Used when a ``Series`` (sub-)class manipulation result should be a ``DataFrame`` (sub-)class, e.g. ``Series.to_frame()``.
347337

348338
Below example shows how to define ``SubclassedSeries`` and ``SubclassedDataFrame`` overriding constructor properties.
349339

doc/source/whatsnew/v1.3.0.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ See :ref:`install.dependencies` and :ref:`install.optional_dependencies` for mor
219219
Other API changes
220220
^^^^^^^^^^^^^^^^^
221221
- Partially initialized :class:`CategoricalDtype` (i.e. those with ``categories=None`` objects will no longer compare as equal to fully initialized dtype objects.
222-
-
222+
- Accessing ``_constructor_expanddim`` on a :class:`DataFrame` and ``_constructor_sliced`` on a :class:`Series` now raise an ``AttributeError``. Previously a ``NotImplementedError`` was raised (:issue:`38782`)
223223
-
224224

225225
.. ---------------------------------------------------------------------------

pandas/core/frame.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -492,20 +492,12 @@ class DataFrame(NDFrame, OpsMixin):
492492
_HANDLED_TYPES = (Series, Index, ExtensionArray, np.ndarray)
493493
_accessors: Set[str] = {"sparse"}
494494
_hidden_attrs: FrozenSet[str] = NDFrame._hidden_attrs | frozenset([])
495-
_constructor_sliced: Type[Series] = Series
496495

497496
@property
498497
def _constructor(self) -> Type[DataFrame]:
499498
return DataFrame
500499

501-
@property
502-
def _constructor_expanddim(self):
503-
# GH#31549 raising NotImplementedError on a property causes trouble
504-
# for `inspect`
505-
def constructor(*args, **kwargs):
506-
raise NotImplementedError("Not supported for DataFrames!")
507-
508-
return constructor
500+
_constructor_sliced: Type[Series] = Series
509501

510502
# ----------------------------------------------------------------------
511503
# Constructors

pandas/core/generic.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -375,14 +375,6 @@ def _constructor(self: FrameOrSeries) -> Type[FrameOrSeries]:
375375
"""
376376
raise AbstractMethodError(self)
377377

378-
@property
379-
def _constructor_expanddim(self):
380-
"""
381-
Used when a manipulation result has one higher dimension as the
382-
original, such as Series.to_frame()
383-
"""
384-
raise NotImplementedError
385-
386378
# ----------------------------------------------------------------------
387379
# Internals
388380

pandas/core/series.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ def _constructor(self) -> Type[Series]:
403403

404404
@property
405405
def _constructor_expanddim(self) -> Type[DataFrame]:
406+
"""
407+
Used when a manipulation result has one higher dimension as the
408+
original, such as Series.to_frame()
409+
"""
406410
from pandas.core.frame import DataFrame
407411

408412
return DataFrame

pandas/tests/frame/test_api.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,11 +322,13 @@ def test_set_flags(self, allows_duplicate_labels, frame_or_series):
322322
assert obj.iloc[key] == 0
323323

324324
def test_constructor_expanddim_lookup(self):
325-
# GH#33628 accessing _constructor_expanddim should not
326-
# raise NotImplementedError
325+
# GH#33628 accessing _constructor_expanddim should not raise NotImplementedError
326+
# GH38782 pandas has no container higher than DatafFame (two-dim), so
327+
# DataFrame._constructor_expand_dim, doesn't make sense, so is removed.
327328
df = DataFrame()
328329

329-
with pytest.raises(NotImplementedError, match="Not supported for DataFrames!"):
330+
msg = "'DataFrame' object has no attribute '_constructor_expanddim'"
331+
with pytest.raises(AttributeError, match=msg):
330332
df._constructor_expanddim(np.arange(27).reshape(3, 3, 3))
331333

332334
@skip_if_no("jinja2")

0 commit comments

Comments
 (0)