Repository: pandas-dev/pandas

Issue:
DEP: Deprecate passing a DataFrame to from_records
- [x] closes #51353 (Replace xxxx with the GitHub issue number)
- [x] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [x] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [x] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [x] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.


cc @jbrockmendel  as discussed, restructuring this allows us to simplify to_arrays immediately


Discussion:
small comment, otherwise LGTM

Patch:
diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst
index 915b7744302c0..234877c834ae3 100644
--- a/doc/source/whatsnew/v3.0.0.rst
+++ b/doc/source/whatsnew/v3.0.0.rst
@@ -128,6 +128,7 @@ Removal of prior version deprecations/changes
 - Removed ``use_nullable_dtypes`` from :func:`read_parquet` (:issue:`51853`)
 - Removed deprecated argument ``obj`` in :meth:`.DataFrameGroupBy.get_group` and :meth:`.SeriesGroupBy.get_group` (:issue:`53545`)
 - Removed deprecated behavior of :meth:`Series.agg` using :meth:`Series.apply` (:issue:`53325`)
+- Removed support for :class:`DataFrame` in :meth:`DataFrame.from_records`(:issue:`51697`)
 - Removed support for ``errors="ignore"`` in :func:`to_datetime`, :func:`to_timedelta` and :func:`to_numeric` (:issue:`55734`)
 - Removed the ``ArrayManager`` (:issue:`55043`)
 - Removed the ``fastpath`` argument from the :class:`Series` constructor (:issue:`55466`)
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
index 0b9d9eba806ea..d435464c51519 100644
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -2112,11 +2112,8 @@ def from_records(
 
         Parameters
         ----------
-        data : structured ndarray, sequence of tuples or dicts, or DataFrame
+        data : structured ndarray, sequence of tuples or dicts
             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.
@@ -2184,21 +2181,10 @@ def from_records(
         3      0     d
         """
         if isinstance(data, DataFrame):
-            warnings.warn(
-                "Passing a DataFrame to DataFrame.from_records is deprecated. Use "
+            raise TypeError(
+                "Passing a DataFrame to DataFrame.from_records is not supported. Use "
                 "set_index and/or drop to modify the DataFrame instead.",
-                FutureWarning,
-                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)
-            if exclude is not None:
-                data = data.drop(columns=exclude)
-            return data.copy(deep=False)
 
         result_index = None
 


Test patch:
diff --git a/pandas/tests/copy_view/test_constructors.py b/pandas/tests/copy_view/test_constructors.py
index f7e78146c86eb..bc931b53b37d0 100644
--- a/pandas/tests/copy_view/test_constructors.py
+++ b/pandas/tests/copy_view/test_constructors.py
@@ -264,17 +264,6 @@ def test_frame_from_numpy_array(copy):
         assert np.shares_memory(get_array(df, 0), arr)
 
 
-def test_dataframe_from_records_with_dataframe():
-    df = DataFrame({"a": [1, 2, 3]})
-    df_orig = df.copy()
-    with tm.assert_produces_warning(FutureWarning):
-        df2 = DataFrame.from_records(df)
-    assert not df._mgr._has_no_reference(0)
-    assert np.shares_memory(get_array(df, "a"), get_array(df2, "a"))
-    df2.iloc[0, 0] = 100
-    tm.assert_frame_equal(df, df_orig)
-
-
 def test_frame_from_dict_of_index():
     idx = Index([1, 2, 3])
     expected = idx.copy(deep=True)
diff --git a/pandas/tests/frame/constructors/test_from_records.py b/pandas/tests/frame/constructors/test_from_records.py
index 3622571f1365d..66fc234e79b4d 100644
--- a/pandas/tests/frame/constructors/test_from_records.py
+++ b/pandas/tests/frame/constructors/test_from_records.py
@@ -17,19 +17,16 @@
     Interval,
     RangeIndex,
     Series,
-    date_range,
 )
 import pandas._testing as tm
 
 
 class TestFromRecords:
     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)})
-        with tm.assert_produces_warning(FutureWarning):
-            res = DataFrame.from_records(df)
-        tm.assert_frame_equal(res, df)
+        # GH#51697
+        df = DataFrame({"a": [1, 2, 3]})
+        with pytest.raises(TypeError, match="not supported"):
+            DataFrame.from_records(df)
 
     def test_from_records_with_datetimes(self):
         # this may fail on certain platforms because of a numpy issue
@@ -195,43 +192,6 @@ def test_from_records_dictlike(self):
         for r in results:
             tm.assert_frame_equal(r, df)
 
-    def test_from_records_with_index_data(self):
-        df = DataFrame(
-            np.random.default_rng(2).standard_normal((10, 3)), columns=["A", "B", "C"]
-        )
-
-        data = np.random.default_rng(2).standard_normal(10)
-        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.default_rng(2).standard_normal((10, 3)), columns=["A", "B", "C"]
-        )
-
-        # should pass
-        with tm.assert_produces_warning(FutureWarning):
-            df1 = DataFrame.from_records(df, index=["C"])
-        tm.assert_index_equal(df1.index, Index(df.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"'None of \[2\] are in the columns'",
-            ]
-        )
-        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:
             def __init__(self, *args) -> None: