Repository: pandas-dev/pandas (python)

Issue:
DEPR: make_block
`make_block` was deprecated and then reverted before the 2.2 release: https://github.com/pandas-dev/pandas/pull/56481

On the dev call today (2024-01-10), it was agreed that a deprecation would be issued during 3.0

Pull request:
DEPR: make_block
- [x] closes #56815 (Replace xxxx with the GitHub issue number)
- [ ] [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
- [ ] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [ ] 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.


Patch:
diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst
index f54f859bd4..2d4fafc3c4 100644
--- a/doc/source/whatsnew/v3.0.0.rst
+++ b/doc/source/whatsnew/v3.0.0.rst
@@ -263,6 +263,7 @@ starting with 3.0, so it can be safely removed from your code.
 Other Deprecations
 ^^^^^^^^^^^^^^^^^^
 
+- Deprecated :func:`core.internals.api.make_block`, use public APIs instead (:issue:`56815`)
 - Deprecated :meth:`.DataFrameGroupby.corrwith` (:issue:`57158`)
 - Deprecated :meth:`Timestamp.utcfromtimestamp`, use ``Timestamp.fromtimestamp(ts, "UTC")`` instead (:issue:`56680`)
 - Deprecated :meth:`Timestamp.utcnow`, use ``Timestamp.now("UTC")`` instead (:issue:`56680`)
@@ -272,7 +273,6 @@ Other Deprecations
 - Deprecated behavior of :meth:`Series.dt.to_pytimedelta`, in a future version this will return a :class:`Series` containing python ``datetime.timedelta`` objects instead of an ``ndarray`` of timedelta; this matches the behavior of other :meth:`Series.dt` properties. (:issue:`57463`)
 - Deprecated parameter ``method`` in :meth:`DataFrame.reindex_like` / :meth:`Series.reindex_like` (:issue:`58667`)
 - Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. (:issue:`57063`)
--
 
 .. ---------------------------------------------------------------------------
 .. _whatsnew_300.prior_deprecations:
diff --git a/pandas/core/internals/api.py b/pandas/core/internals/api.py
index 24bfad4791..04944db2eb 100644
--- a/pandas/core/internals/api.py
+++ b/pandas/core/internals/api.py
@@ -10,6 +10,7 @@ authors
 from __future__ import annotations
 
 from typing import TYPE_CHECKING
+import warnings
 
 import numpy as np
 
@@ -87,6 +88,15 @@ def make_block(
     - Block.make_block_same_class
     - Block.__init__
     """
+    warnings.warn(
+        # GH#56815
+        "make_block is deprecated and will be removed in a future version. "
+        "Use pd.api.internals.create_dataframe_from_blocks or "
+        "(recommended) higher-level public APIs instead.",
+        DeprecationWarning,
+        stacklevel=2,
+    )
+
     if dtype is not None:
         dtype = pandas_dtype(dtype)
 
diff --git a/pandas/io/feather_format.py b/pandas/io/feather_format.py
index 8132167fbe..16d4e1f9ea 100644
--- a/pandas/io/feather_format.py
+++ b/pandas/io/feather_format.py
@@ -6,6 +6,7 @@ from typing import (
     TYPE_CHECKING,
     Any,
 )
+import warnings
 
 from pandas._config import using_pyarrow_string_dtype
 
@@ -131,9 +132,16 @@ def read_feather(
         path, "rb", storage_options=storage_options, is_text=False
     ) as handles:
         if dtype_backend is lib.no_default and not using_pyarrow_string_dtype():
-            return feather.read_feather(
-                handles.handle, columns=columns, use_threads=bool(use_threads)
-            )
+            with warnings.catch_warnings():
+                warnings.filterwarnings(
+                    "ignore",
+                    "make_block is deprecated",
+                    DeprecationWarning,
+                )
+
+                return feather.read_feather(
+                    handles.handle, columns=columns, use_threads=bool(use_threads)
+                )
 
         pa_table = feather.read_table(
             handles.handle, columns=columns, use_threads=bool(use_threads)
diff --git a/pandas/io/parquet.py b/pandas/io/parquet.py
index 08983ceed4..306b144811 100644
--- a/pandas/io/parquet.py
+++ b/pandas/io/parquet.py
@@ -10,7 +10,10 @@ from typing import (
     Any,
     Literal,
 )
-from warnings import catch_warnings
+from warnings import (
+    catch_warnings,
+    filterwarnings,
+)
 
 from pandas._config import using_pyarrow_string_dtype
 
@@ -271,7 +274,13 @@ class PyArrowImpl(BaseImpl):
                 filters=filters,
                 **kwargs,
             )
-            result = pa_table.to_pandas(**to_pandas_kwargs)
+            with catch_warnings():
+                filterwarnings(
+                    "ignore",
+                    "make_block is deprecated",
+                    DeprecationWarning,
+                )
+                result = pa_table.to_pandas(**to_pandas_kwargs)
 
             if pa_table.schema.metadata:
                 if b"PANDAS_ATTRS" in pa_table.schema.metadata:
@@ -384,7 +393,15 @@ class FastParquetImpl(BaseImpl):
 
         try:
             parquet_file = self.api.ParquetFile(path, **parquet_kwargs)
-            return parquet_file.to_pandas(columns=columns, filters=filters, **kwargs)
+            with catch_warnings():
+                filterwarnings(
+                    "ignore",
+                    "make_block is deprecated",
+                    DeprecationWarning,
+                )
+                return parquet_file.to_pandas(
+                    columns=columns, filters=filters, **kwargs
+                )
         finally:
             if handles is not None:
                 handles.close()
diff --git a/pandas/io/parsers/arrow_parser_wrapper.py b/pandas/io/parsers/arrow_parser_wrapper.py
index 8b6f7d5750..cffdb28e2c 100644
--- a/pandas/io/parsers/arrow_parser_wrapper.py
+++ b/pandas/io/parsers/arrow_parser_wrapper.py
@@ -287,17 +287,23 @@ class ArrowParserWrapper(ParserBase):
 
             table = table.cast(new_schema)
 
-        if dtype_backend == "pyarrow":
-            frame = table.to_pandas(types_mapper=pd.ArrowDtype)
-        elif dtype_backend == "numpy_nullable":
-            # Modify the default mapping to also
-            # map null to Int64 (to match other engines)
-            dtype_mapping = _arrow_dtype_mapping()
-            dtype_mapping[pa.null()] = pd.Int64Dtype()
-            frame = table.to_pandas(types_mapper=dtype_mapping.get)
-        elif using_pyarrow_string_dtype():
-            frame = table.to_pandas(types_mapper=arrow_string_types_mapper())
+        with warnings.catch_warnings():
+            warnings.filterwarnings(
+                "ignore",
+                "make_block is deprecated",
+                DeprecationWarning,
+            )
+            if dtype_backend == "pyarrow":
+                frame = table.to_pandas(types_mapper=pd.ArrowDtype)
+            elif dtype_backend == "numpy_nullable":
+                # Modify the default mapping to also
+                # map null to Int64 (to match other engines)
+                dtype_mapping = _arrow_dtype_mapping()
+                dtype_mapping[pa.null()] = pd.Int64Dtype()
+                frame = table.to_pandas(types_mapper=dtype_mapping.get)
+            elif using_pyarrow_string_dtype():
+                frame = table.to_pandas(types_mapper=arrow_string_types_mapper())
 
-        else:
-            frame = table.to_pandas()
+            else:
+                frame = table.to_pandas()
         return self._finalize_pandas_output(frame)


Test patch:
diff --git a/pandas/tests/internals/test_api.py b/pandas/tests/internals/test_api.py
index c189d5248b..591157bbe8 100644
--- a/pandas/tests/internals/test_api.py
+++ b/pandas/tests/internals/test_api.py
@@ -44,7 +44,10 @@ def test_namespace():
 def test_make_block_2d_with_dti():
     # GH#41168
     dti = pd.date_range("2012", periods=3, tz="UTC")
-    blk = api.make_block(dti, placement=[0])
+
+    msg = "make_block is deprecated"
+    with tm.assert_produces_warning(DeprecationWarning, match=msg):
+        blk = api.make_block(dti, placement=[0])
 
     assert blk.shape == (1, 3)
     assert blk.values.shape == (1, 3)
diff --git a/pandas/tests/internals/test_internals.py b/pandas/tests/internals/test_internals.py
index 60ca47b52b..fca1ed39c0 100644
--- a/pandas/tests/internals/test_internals.py
+++ b/pandas/tests/internals/test_internals.py
@@ -1368,8 +1368,10 @@ def test_validate_ndim():
     placement = BlockPlacement(slice(2))
     msg = r"Wrong number of dimensions. values.ndim != ndim \[1 != 2\]"
 
+    depr_msg = "make_block is deprecated"
     with pytest.raises(ValueError, match=msg):
-        make_block(values, placement, ndim=2)
+        with tm.assert_produces_warning(DeprecationWarning, match=depr_msg):
+            make_block(values, placement, ndim=2)
 
 
 def test_block_shape():
@@ -1384,8 +1386,12 @@ def test_make_block_no_pandas_array(block_maker):
     # https://github.com/pandas-dev/pandas/pull/24866
     arr = pd.arrays.NumpyExtensionArray(np.array([1, 2]))
 
+    depr_msg = "make_block is deprecated"
+    warn = DeprecationWarning if block_maker is make_block else None
+
     # NumpyExtensionArray, no dtype
-    result = block_maker(arr, BlockPlacement(slice(len(arr))), ndim=arr.ndim)
+    with tm.assert_produces_warning(warn, match=depr_msg):
+        result = block_maker(arr, BlockPlacement(slice(len(arr))), ndim=arr.ndim)
     assert result.dtype.kind in ["i", "u"]
 
     if block_maker is make_block:
@@ -1393,14 +1399,16 @@ def test_make_block_no_pandas_array(block_maker):
         assert result.is_extension is False
 
         # NumpyExtensionArray, NumpyEADtype
-        result = block_maker(arr, slice(len(arr)), dtype=arr.dtype, ndim=arr.ndim)
+        with tm.assert_produces_warning(warn, match=depr_msg):
+            result = block_maker(arr, slice(len(arr)), dtype=arr.dtype, ndim=arr.ndim)
         assert result.dtype.kind in ["i", "u"]
         assert result.is_extension is False
 
         # new_block no longer accepts dtype keyword
         # ndarray, NumpyEADtype
-        result = block_maker(
-            arr.to_numpy(), slice(len(arr)), dtype=arr.dtype, ndim=arr.ndim
-        )
+        with tm.assert_produces_warning(warn, match=depr_msg):
+            result = block_maker(
+                arr.to_numpy(), slice(len(arr)), dtype=arr.dtype, ndim=arr.ndim
+            )
         assert result.dtype.kind in ["i", "u"]
         assert result.is_extension is False
diff --git a/pandas/tests/io/test_parquet.py b/pandas/tests/io/test_parquet.py
index 35275f3c23..af492b967b 100644
--- a/pandas/tests/io/test_parquet.py
+++ b/pandas/tests/io/test_parquet.py
@@ -985,6 +985,7 @@ class TestParquetPyArrow(Base):
             result = read_parquet(path, pa, filters=[("a", "==", 0)])
         assert len(result) == 1
 
+    @pytest.mark.filterwarnings("ignore:make_block is deprecated:DeprecationWarning")
     def test_read_dtype_backend_pyarrow_config(self, pa, df_full):
         import pyarrow