Skip to content

Commit ff4c6d1

Browse files
Backport PR #45523: DEPR: restore to_frame() name=None behaviour but deprecate it (#45529)
Co-authored-by: Joris Van den Bossche <[email protected]>
1 parent 7501612 commit ff4c6d1

File tree

6 files changed

+51
-8
lines changed

6 files changed

+51
-8
lines changed

doc/source/whatsnew/v1.4.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,7 @@ Other Deprecations
696696
- Deprecated the behavior of :meth:`Timestamp.utcfromtimestamp`, in the future it will return a timezone-aware UTC :class:`Timestamp` (:issue:`22451`)
697697
- Deprecated :meth:`NaT.freq` (:issue:`45071`)
698698
- Deprecated behavior of :class:`Series` and :class:`DataFrame` construction when passed float-dtype data containing ``NaN`` and an integer dtype ignoring the dtype argument; in a future version this will raise (:issue:`40110`)
699+
- Deprecated the behaviour of :meth:`Series.to_frame` and :meth:`Index.to_frame` to ignore the ``name`` argument when ``name=None``. Currently, this means to preserve the existing name, but in the future explicitly passing ``name=None`` will set ``None`` as the name of the column in the resulting DataFrame (:issue:`44212`)
699700

700701
.. ---------------------------------------------------------------------------
701702
@@ -1041,7 +1042,6 @@ Other
10411042
- Bug in :meth:`CustomBusinessMonthBegin.__add__` (:meth:`CustomBusinessMonthEnd.__add__`) not applying the extra ``offset`` parameter when beginning (end) of the target month is already a business day (:issue:`41356`)
10421043
- Bug in :meth:`RangeIndex.union` with another ``RangeIndex`` with matching (even) ``step`` and starts differing by strictly less than ``step / 2`` (:issue:`44019`)
10431044
- Bug in :meth:`RangeIndex.difference` with ``sort=None`` and ``step<0`` failing to sort (:issue:`44085`)
1044-
- Bug in :meth:`Series.to_frame` and :meth:`Index.to_frame` ignoring the ``name`` argument when ``name=None`` is explicitly passed (:issue:`44212`)
10451045
- Bug in :meth:`Series.replace` and :meth:`DataFrame.replace` with ``value=None`` and ExtensionDtypes (:issue:`44270`, :issue:`37899`)
10461046
- Bug in :meth:`FloatingArray.equals` failing to consider two arrays equal if they contain ``np.nan`` values (:issue:`44382`)
10471047
- Bug in :meth:`DataFrame.shift` with ``axis=1`` and ``ExtensionDtype`` columns incorrectly raising when an incompatible ``fill_value`` is passed (:issue:`44564`)

pandas/core/indexes/base.py

+11
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,17 @@ def to_frame(
16251625
"""
16261626
from pandas import DataFrame
16271627

1628+
if name is None:
1629+
warnings.warn(
1630+
"Explicitly passing `name=None` currently preserves the Index's name "
1631+
"or uses a default name of 0. This behaviour is deprecated, and in "
1632+
"the future `None` will be used as the name of the resulting "
1633+
"DataFrame column.",
1634+
FutureWarning,
1635+
stacklevel=find_stack_level(),
1636+
)
1637+
name = lib.no_default
1638+
16281639
if name is lib.no_default:
16291640
name = self.name or 0
16301641
result = DataFrame({name: self._values.copy()})

pandas/core/indexes/multi.py

+11
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,17 @@ def to_frame(self, index: bool = True, name=lib.no_default) -> DataFrame:
17621762
"""
17631763
from pandas import DataFrame
17641764

1765+
if name is None:
1766+
warnings.warn(
1767+
"Explicitly passing `name=None` currently preserves the Index's name "
1768+
"or uses a default name of 0. This behaviour is deprecated, and in "
1769+
"the future `None` will be used as the name of the resulting "
1770+
"DataFrame column.",
1771+
FutureWarning,
1772+
stacklevel=find_stack_level(),
1773+
)
1774+
name = lib.no_default
1775+
17651776
if name is not lib.no_default:
17661777
if not is_list_like(name):
17671778
raise TypeError("'name' must be a list / sequence of column names.")

pandas/core/series.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -1752,7 +1752,7 @@ def to_frame(self, name: Hashable = lib.no_default) -> DataFrame:
17521752
17531753
Parameters
17541754
----------
1755-
name : object, default None
1755+
name : object, optional
17561756
The passed name should substitute for the series name (if it has
17571757
one).
17581758
@@ -1771,6 +1771,17 @@ def to_frame(self, name: Hashable = lib.no_default) -> DataFrame:
17711771
1 b
17721772
2 c
17731773
"""
1774+
if name is None:
1775+
warnings.warn(
1776+
"Explicitly passing `name=None` currently preserves the Series' name "
1777+
"or uses a default name of 0. This behaviour is deprecated, and in "
1778+
"the future `None` will be used as the name of the resulting "
1779+
"DataFrame column.",
1780+
FutureWarning,
1781+
stacklevel=find_stack_level(),
1782+
)
1783+
name = lib.no_default
1784+
17741785
columns: Index
17751786
if name is lib.no_default:
17761787
name = self.name

pandas/tests/indexes/datetimes/methods/test_to_frame.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@ def test_to_frame_datetime_tz(self):
1717
def test_to_frame_respects_none_name(self):
1818
# GH#44212 if we explicitly pass name=None, then that should be respected,
1919
# not changed to 0
20+
# GH-45448 this is first deprecated to only change in the future
2021
idx = date_range(start="2019-01-01", end="2019-01-30", freq="D", tz="UTC")
21-
result = idx.to_frame(name=None)
22-
exp_idx = Index([None], dtype=object)
22+
with tm.assert_produces_warning(FutureWarning):
23+
result = idx.to_frame(name=None)
24+
# exp_idx = Index([None], dtype=object)
25+
exp_idx = Index([0])
2326
tm.assert_index_equal(exp_idx, result.columns)
2427

25-
result = idx.rename("foo").to_frame(name=None)
28+
with tm.assert_produces_warning(FutureWarning):
29+
result = idx.rename("foo").to_frame(name=None)
30+
exp_idx = Index(["foo"], dtype=object)
2631
tm.assert_index_equal(exp_idx, result.columns)

pandas/tests/series/methods/test_to_frame.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@ class TestToFrame:
1010
def test_to_frame_respects_name_none(self):
1111
# GH#44212 if we explicitly pass name=None, then that should be respected,
1212
# not changed to 0
13+
# GH-45448 this is first deprecated to only change in the future
1314
ser = Series(range(3))
14-
result = ser.to_frame(None)
15+
with tm.assert_produces_warning(FutureWarning):
16+
result = ser.to_frame(None)
1517

16-
exp_index = Index([None], dtype=object)
18+
# exp_index = Index([None], dtype=object)
19+
exp_index = Index([0])
1720
tm.assert_index_equal(result.columns, exp_index)
1821

19-
result = ser.rename("foo").to_frame(None)
22+
with tm.assert_produces_warning(FutureWarning):
23+
result = ser.rename("foo").to_frame(None)
24+
exp_index = Index(["foo"], dtype=object)
2025
tm.assert_index_equal(result.columns, exp_index)
2126

2227
def test_to_frame(self, datetime_series):

0 commit comments

Comments
 (0)