From 0104dbd5a0af250894aa7c4c090050dd0a5f5152 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Tue, 28 Feb 2023 23:07:21 +0100 Subject: [PATCH 1/7] DEP: Deprecate passing a DataFrame to from_records --- pandas/core/frame.py | 17 ++++++++++++- .../frame/constructors/test_from_records.py | 24 ++++++++++++------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index dbbe2c0751f3a..679c9d5cadc03 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2171,6 +2171,21 @@ def from_records( 2 1 c 3 0 d """ + if isinstance(data, DataFrame): + warnings.warn( + "Passing a DataFrame to DataFrame.from_records is deprecated. Use " + "set_index and/or drop instead to modify the DataFrame.", + FutureWarning, + stacklevel=find_stack_level(), + ) + if columns is not None: + data = data[columns] + if index is not None: + data = data.set_index(index) + if exclude is not None: + data = data.drop(columns=exclude) + return data + result_index = None # Make a copy of the input columns so we can modify it @@ -2238,7 +2253,7 @@ def maybe_reorder( arrays, arr_columns, columns, index ) - elif isinstance(data, (np.ndarray, DataFrame)): + elif isinstance(data, np.ndarray): arrays, columns = to_arrays(data, columns) arr_columns = columns else: diff --git a/pandas/tests/frame/constructors/test_from_records.py b/pandas/tests/frame/constructors/test_from_records.py index 18bf633d60186..0ba4f6d249e6d 100644 --- a/pandas/tests/frame/constructors/test_from_records.py +++ b/pandas/tests/frame/constructors/test_from_records.py @@ -25,7 +25,8 @@ def test_from_records_dt64tz_frame(self): # GH#51162 don't lose tz when calling from_records with DataFrame input dti = date_range("2016-01-01", periods=10, tz="US/Pacific") df = DataFrame({i: dti for i in range(4)}) - res = DataFrame.from_records(df) + with tm.assert_produces_warning(FutureWarning): + res = DataFrame.from_records(df) tm.assert_frame_equal(res, df) def test_from_records_with_datetimes(self): @@ -177,29 +178,34 @@ def test_from_records_with_index_data(self): df = DataFrame(np.random.randn(10, 3), columns=["A", "B", "C"]) data = np.random.randn(10) - df1 = DataFrame.from_records(df, index=data) + with tm.assert_produces_warning(FutureWarning): + df1 = DataFrame.from_records(df, index=data) tm.assert_index_equal(df1.index, Index(data)) def test_from_records_bad_index_column(self): df = DataFrame(np.random.randn(10, 3), columns=["A", "B", "C"]) # should pass - df1 = DataFrame.from_records(df, index=["C"]) + with tm.assert_produces_warning(FutureWarning): + df1 = DataFrame.from_records(df, index=["C"]) tm.assert_index_equal(df1.index, Index(df.C)) - df1 = DataFrame.from_records(df, index="C") + with tm.assert_produces_warning(FutureWarning): + df1 = DataFrame.from_records(df, index="C") tm.assert_index_equal(df1.index, Index(df.C)) # should fail msg = "|".join( [ - r"Length of values \(10\) does not match length of index \(1\)", + r"'None of \[2\] are in the columns'", ] ) - with pytest.raises(ValueError, match=msg): - DataFrame.from_records(df, index=[2]) - with pytest.raises(KeyError, match=r"^2$"): - DataFrame.from_records(df, index=2) + with pytest.raises(KeyError, match=msg): + with tm.assert_produces_warning(FutureWarning): + DataFrame.from_records(df, index=[2]) + with pytest.raises(KeyError, match=msg): + with tm.assert_produces_warning(FutureWarning): + DataFrame.from_records(df, index=2) def test_from_records_non_tuple(self): class Record: From b7f74f3f95751d91496135ff7898b97ec8d3dfcf Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Tue, 28 Feb 2023 23:08:20 +0100 Subject: [PATCH 2/7] DEP: Deprecate passing a DataFrame to from_records --- doc/source/whatsnew/v2.1.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 45b5c16415f9d..5b040bcf6c564 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -93,7 +93,7 @@ Other API changes Deprecations ~~~~~~~~~~~~ - Deprecated accepting slices in :meth:`DataFrame.take`, call ``obj[slicer]`` or pass a sequence of integers instead (:issue:`51539`) -- +- Deprecated passing a :class:`DataFrame` to :meth:`DataFrame.from_records`, use :meth:`DataFrame.set_index` or :meth:`DataFrame.drop` instead (:issue:`51353`) .. --------------------------------------------------------------------------- .. _whatsnew_210.performance: From cce319d8d8bbd5743a7b202b15d298fbcfce79ab Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Tue, 28 Feb 2023 23:10:30 +0100 Subject: [PATCH 3/7] Remove unnecessary code --- pandas/core/internals/construction.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/pandas/core/internals/construction.py b/pandas/core/internals/construction.py index 4dbdd5e5b77fe..e94e4b2a0b563 100644 --- a/pandas/core/internals/construction.py +++ b/pandas/core/internals/construction.py @@ -772,19 +772,6 @@ def to_arrays( ----- Ensures that len(result_arrays) == len(result_index). """ - if isinstance(data, ABCDataFrame): - # see test_from_records_with_index_data, test_from_records_bad_index_column - if columns is not None: - arrays = [ - data._ixs(i, axis=1)._values - for i, col in enumerate(data.columns) - if col in columns - ] - else: - columns = data.columns - arrays = [data._ixs(i, axis=1)._values for i in range(len(columns))] - - return arrays, columns if not len(data): if isinstance(data, np.ndarray): From ed29a91340344b3c42e33261972927285f0a2a45 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Tue, 28 Feb 2023 23:11:45 +0100 Subject: [PATCH 4/7] Fix --- pandas/core/frame.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 679c9d5cadc03..b89adff65ab95 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2179,6 +2179,8 @@ def from_records( stacklevel=find_stack_level(), ) if columns is not None: + if is_scalar(columns): + columns = [columns] data = data[columns] if index is not None: data = data.set_index(index) From 67d01ee56d59b601e8593f729493fc9c2c5dadbb Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Tue, 28 Feb 2023 23:13:36 +0100 Subject: [PATCH 5/7] Add whatsnew --- pandas/core/frame.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index b89adff65ab95..c51aba936555f 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2109,6 +2109,9 @@ def from_records( ---------- data : structured ndarray, sequence of tuples or dicts, or DataFrame Structured input data. + + .. deprecated:: 2.1.0 + Passing a DataFrame is deprecated. index : str, list of fields, array-like Field of array to use as the index, alternately a specific set of input labels to use. From f146cac354b7f7f741937cc427e9eb7c9055133c Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Wed, 1 Mar 2023 00:41:26 +0100 Subject: [PATCH 6/7] Rephrase --- pandas/core/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index c51aba936555f..ea8a6cfc99fd1 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2177,7 +2177,7 @@ def from_records( if isinstance(data, DataFrame): warnings.warn( "Passing a DataFrame to DataFrame.from_records is deprecated. Use " - "set_index and/or drop instead to modify the DataFrame.", + "set_index and/or drop to modify the DataFrame instead.", FutureWarning, stacklevel=find_stack_level(), ) From 5394e372a136a4c99940c2f62f79c86a21f5c65a Mon Sep 17 00:00:00 2001 From: Patrick Hoefler <61934744+phofl@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:35:43 +0100 Subject: [PATCH 7/7] Update v2.1.0.rst --- doc/source/whatsnew/v2.1.0.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 03060f94f1258..2ac20e97409e7 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -93,8 +93,9 @@ Other API changes Deprecations ~~~~~~~~~~~~ - Deprecating pinning ``group.name`` to each group in :meth:`SeriesGroupBy.aggregate` aggregations; if your operation requires utilizing the groupby keys, iterate over the groupby object instead (:issue:`41090`) -- Deprecated accepting slices in :meth:`DataFrame.take`, call ``obj[slicer]`` or pass a sequence of integers instead (:issue:`51539`) - Deprecated passing a :class:`DataFrame` to :meth:`DataFrame.from_records`, use :meth:`DataFrame.set_index` or :meth:`DataFrame.drop` instead (:issue:`51353`) +- Deprecated accepting slices in :meth:`DataFrame.take`, call ``obj[slicer]`` or pass a sequence of integers instead (:issue:`51539`) +- .. --------------------------------------------------------------------------- .. _whatsnew_210.performance: