From 7306256653313d5e1806ac10ee1527272034747c Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 14 Sep 2023 15:46:16 -0700 Subject: [PATCH 1/7] DEPR: deprecate exposing blocks in core.internals --- doc/source/whatsnew/v2.2.0.rst | 2 ++ pandas/core/internals/__init__.py | 31 +++++++++++++++++------ pandas/core/internals/api.py | 40 +++++++++++++++++++++++++++--- pandas/tests/internals/test_api.py | 35 ++++++++++++++++++++++---- 4 files changed, 93 insertions(+), 15 deletions(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index 54e855f61905a..93c4abad6146d 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -169,6 +169,8 @@ Deprecations - Deprecated strings ``T``, ``S``, ``L``, ``U``, and ``N`` denoting frequencies in :class:`Minute`, :class:`Second`, :class:`Milli`, :class:`Micro`, :class:`Nano` (:issue:`52536`) - Deprecated strings ``T``, ``S``, ``L``, ``U``, and ``N`` denoting units in :class:`Timedelta` (:issue:`52536`) - Deprecated the extension test classes ``BaseNoReduceTests``, ``BaseBooleanReduceTests``, and ``BaseNumericReduceTests``, use ``BaseReduceTests`` instead (:issue:`54663`) +- Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, ``DatetimeTZBlock``, and ``make_block``, use public APIs instead (:issue:`??`) +- .. --------------------------------------------------------------------------- .. _whatsnew_220.performance: diff --git a/pandas/core/internals/__init__.py b/pandas/core/internals/__init__.py index 284f8ef135d99..77134bf2667c7 100644 --- a/pandas/core/internals/__init__.py +++ b/pandas/core/internals/__init__.py @@ -1,4 +1,3 @@ -from pandas.core.internals.api import make_block from pandas.core.internals.array_manager import ( ArrayManager, SingleArrayManager, @@ -7,11 +6,6 @@ DataManager, SingleDataManager, ) -from pandas.core.internals.blocks import ( # io.pytables, io.packers - Block, - DatetimeTZBlock, - ExtensionBlock, -) from pandas.core.internals.concat import concatenate_managers from pandas.core.internals.managers import ( BlockManager, @@ -41,7 +35,14 @@ def __getattr__(name: str): from pandas.util._exceptions import find_stack_level - if name in ["NumericBlock", "ObjectBlock"]: + if name in [ + "NumericBlock", + "ObjectBlock", + "Block", + "ExtensionBlock", + "DatetimeTZBlock", + "make_block", + ]: warnings.warn( f"{name} is deprecated and will be removed in a future version. " "Use public APIs instead.", @@ -52,6 +53,22 @@ def __getattr__(name: str): from pandas.core.internals.blocks import NumericBlock return NumericBlock + elif name == "DatetimeTZBlock": + from pandas.core.internals.blocks import DatetimeTZBlock + + return DatetimeTZBlock + elif name == "ExtensionBlock": + from pandas.core.internals.blocks import ExtensionBlock + + return ExtensionBlock + elif name == "Block": + from pandas.core.internals.blocks import Block + + return Block + elif name == "make_block": + from pandas.core.internals.api import make_block + + return make_block else: from pandas.core.internals.blocks import ObjectBlock diff --git a/pandas/core/internals/api.py b/pandas/core/internals/api.py index 10e6b76e985b3..4ede7498ec44c 100644 --- a/pandas/core/internals/api.py +++ b/pandas/core/internals/api.py @@ -23,9 +23,6 @@ from pandas.core.arrays import DatetimeArray from pandas.core.construction import extract_array from pandas.core.internals.blocks import ( - Block, - DatetimeTZBlock, - ExtensionBlock, check_ndim, ensure_block_shape, extract_pandas_array, @@ -36,6 +33,8 @@ if TYPE_CHECKING: from pandas._typing import Dtype + from pandas.core.internals.blocks import Block + def make_block( values, placement, klass=None, ndim=None, dtype: Dtype | None = None @@ -56,6 +55,11 @@ def make_block( values, dtype = extract_pandas_array(values, dtype, ndim) + from pandas.core.internals.blocks import ( + DatetimeTZBlock, + ExtensionBlock, + ) + if klass is ExtensionBlock and isinstance(values.dtype, PeriodDtype): # GH-44681 changed PeriodArray to be stored in the 2D # NDArrayBackedExtensionBlock instead of ExtensionBlock @@ -105,3 +109,33 @@ def maybe_infer_ndim(values, placement: BlockPlacement, ndim: int | None) -> int else: ndim = values.ndim return ndim + + +def __getattr__(name: str): + import warnings + + from pandas.util._exceptions import find_stack_level + + if name in ["Block", "ExtensionBlock", "DatetimeTZBlock"]: + warnings.warn( + f"{name} is deprecated and will be removed in a future version. " + "Use public APIs instead.", + DeprecationWarning, + stacklevel=find_stack_level(), + ) + if name == "Block": + from pandas.core.internals.blocks import Block + + return Block + + elif name == "DatetimeTZBlock": + from pandas.core.internals.blocks import DatetimeTZBlock + + return DatetimeTZBlock + + elif name == "ExtensionBlock": + from pandas.core.internals.blocks import ExtensionBlock + + return ExtensionBlock + + raise AttributeError(f"module 'pandas.core.internals' has no attribute '{name}'") diff --git a/pandas/tests/internals/test_api.py b/pandas/tests/internals/test_api.py index 5cd6c718260ea..bfa639fac9545 100644 --- a/pandas/tests/internals/test_api.py +++ b/pandas/tests/internals/test_api.py @@ -3,13 +3,19 @@ in core.internals """ +import pytest + import pandas as pd +import pandas._testing as tm from pandas.core import internals from pandas.core.internals import api def test_internals_api(): - assert internals.make_block is api.make_block + msg = "make_block is deprecated.* Use public APIs instead" + with tm.assert_produces_warning(DeprecationWarning, match=msg): + mb = internals.make_block + assert mb is api.make_block def test_namespace(): @@ -26,10 +32,6 @@ def test_namespace(): "ops", ] expected = [ - "Block", - "DatetimeTZBlock", - "ExtensionBlock", - "make_block", "DataManager", "ArrayManager", "BlockManager", @@ -44,6 +46,29 @@ def test_namespace(): assert set(result) == set(expected + modules) +@pytest.mark.parametrize( + "name", + [ + "NumericBlock", + "ObjectBlock", + "Block", + "ExtensionBlock", + "DatetimeTZBlock", + "make_block", + ], +) +def test_deprecations(name): + msg = f"{name} is deprecated.* Use public APIs instead" + with tm.assert_produces_warning(DeprecationWarning, match=msg): + getattr(internals, name) + + if name not in ["make_block", "NumericBlock", "ObjectBlock"]: + # NumericBlock and ObjectBlock are not in the internals.api namespace; + # make_block is not deprecated there. + with tm.assert_produces_warning(DeprecationWarning, match=msg): + getattr(api, name) + + def test_make_block_2d_with_dti(): # GH#41168 dti = pd.date_range("2012", periods=3, tz="UTC") From e4e5cebf66a7080d65ab76e60fdc24b58f239748 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 14 Sep 2023 15:55:01 -0700 Subject: [PATCH 2/7] GH ref --- doc/source/whatsnew/v2.2.0.rst | 2 +- pandas/core/internals/__init__.py | 1 + pandas/core/internals/api.py | 1 + pandas/tests/internals/test_api.py | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index 93c4abad6146d..b1a79527b2378 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -149,6 +149,7 @@ Other API changes Deprecations ~~~~~~~~~~~~ - Changed :meth:`Timedelta.resolution_string` to return ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`) +- Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, ``DatetimeTZBlock``, and ``make_block``, use public APIs instead (:issue:`55139`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_clipboard`. (:issue:`54229`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_csv` except ``path_or_buf``. (:issue:`54229`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_dict`. (:issue:`54229`) @@ -169,7 +170,6 @@ Deprecations - Deprecated strings ``T``, ``S``, ``L``, ``U``, and ``N`` denoting frequencies in :class:`Minute`, :class:`Second`, :class:`Milli`, :class:`Micro`, :class:`Nano` (:issue:`52536`) - Deprecated strings ``T``, ``S``, ``L``, ``U``, and ``N`` denoting units in :class:`Timedelta` (:issue:`52536`) - Deprecated the extension test classes ``BaseNoReduceTests``, ``BaseBooleanReduceTests``, and ``BaseNumericReduceTests``, use ``BaseReduceTests`` instead (:issue:`54663`) -- Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, ``DatetimeTZBlock``, and ``make_block``, use public APIs instead (:issue:`??`) - .. --------------------------------------------------------------------------- diff --git a/pandas/core/internals/__init__.py b/pandas/core/internals/__init__.py index 77134bf2667c7..f4c78fe0ac98a 100644 --- a/pandas/core/internals/__init__.py +++ b/pandas/core/internals/__init__.py @@ -31,6 +31,7 @@ def __getattr__(name: str): + # GH#55139 import warnings from pandas.util._exceptions import find_stack_level diff --git a/pandas/core/internals/api.py b/pandas/core/internals/api.py index 4ede7498ec44c..59f6919405c59 100644 --- a/pandas/core/internals/api.py +++ b/pandas/core/internals/api.py @@ -112,6 +112,7 @@ def maybe_infer_ndim(values, placement: BlockPlacement, ndim: int | None) -> int def __getattr__(name: str): + # GH#55139 import warnings from pandas.util._exceptions import find_stack_level diff --git a/pandas/tests/internals/test_api.py b/pandas/tests/internals/test_api.py index bfa639fac9545..7d0797449d9e9 100644 --- a/pandas/tests/internals/test_api.py +++ b/pandas/tests/internals/test_api.py @@ -58,6 +58,7 @@ def test_namespace(): ], ) def test_deprecations(name): + # GH#55139 msg = f"{name} is deprecated.* Use public APIs instead" with tm.assert_produces_warning(DeprecationWarning, match=msg): getattr(internals, name) From a3262a222afda80f1d8373fbfe2fa06c73179eb5 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 15 Sep 2023 07:38:55 -0700 Subject: [PATCH 3/7] Suppress on import --- pandas/tests/internals/test_internals.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pandas/tests/internals/test_internals.py b/pandas/tests/internals/test_internals.py index 597bc2975268e..e228559a5f25d 100644 --- a/pandas/tests/internals/test_internals.py +++ b/pandas/tests/internals/test_internals.py @@ -4,6 +4,7 @@ ) import itertools import re +import warnings import numpy as np import pytest @@ -36,7 +37,6 @@ from pandas.core.internals import ( BlockManager, SingleBlockManager, - make_block, ) from pandas.core.internals.blocks import ( ensure_block_shape, @@ -44,6 +44,11 @@ new_block, ) +with warnings.catch_warnings(): + warnings.simplefilter("ignore") + from pandas.core.internals import make_block + + # this file contains BlockManager specific tests # TODO(ArrayManager) factor out interleave_dtype tests pytestmark = td.skip_array_manager_invalid_test From c4d453916e2269a0063077261fc113d18e1510a6 Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 18 Sep 2023 13:58:06 -0700 Subject: [PATCH 4/7] revert make_block deprecation --- doc/source/whatsnew/v2.2.0.rst | 2 +- pandas/core/internals/__init__.py | 6 +----- pandas/tests/internals/test_api.py | 12 ++++-------- pandas/tests/internals/test_internals.py | 7 +------ 4 files changed, 7 insertions(+), 20 deletions(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index dc92b019b1afd..e2d8d55055a94 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -177,7 +177,7 @@ Other API changes Deprecations ~~~~~~~~~~~~ - Changed :meth:`Timedelta.resolution_string` to return ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`) -- Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, ``DatetimeTZBlock``, and ``make_block``, use public APIs instead (:issue:`55139`) +- Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, and ``DatetimeTZBlock``, use public APIs instead (:issue:`55139`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_clipboard`. (:issue:`54229`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_csv` except ``path_or_buf``. (:issue:`54229`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_dict`. (:issue:`54229`) diff --git a/pandas/core/internals/__init__.py b/pandas/core/internals/__init__.py index f4c78fe0ac98a..4aef605c31bf8 100644 --- a/pandas/core/internals/__init__.py +++ b/pandas/core/internals/__init__.py @@ -1,3 +1,4 @@ +from pandas.core.internals.api import make_block # 2023-09-18 pyarrow uses this from pandas.core.internals.array_manager import ( ArrayManager, SingleArrayManager, @@ -42,7 +43,6 @@ def __getattr__(name: str): "Block", "ExtensionBlock", "DatetimeTZBlock", - "make_block", ]: warnings.warn( f"{name} is deprecated and will be removed in a future version. " @@ -66,10 +66,6 @@ def __getattr__(name: str): from pandas.core.internals.blocks import Block return Block - elif name == "make_block": - from pandas.core.internals.api import make_block - - return make_block else: from pandas.core.internals.blocks import ObjectBlock diff --git a/pandas/tests/internals/test_api.py b/pandas/tests/internals/test_api.py index 7d0797449d9e9..3be1dfb22a5a2 100644 --- a/pandas/tests/internals/test_api.py +++ b/pandas/tests/internals/test_api.py @@ -12,10 +12,7 @@ def test_internals_api(): - msg = "make_block is deprecated.* Use public APIs instead" - with tm.assert_produces_warning(DeprecationWarning, match=msg): - mb = internals.make_block - assert mb is api.make_block + assert internals.make_block is api.make_block def test_namespace(): @@ -32,6 +29,7 @@ def test_namespace(): "ops", ] expected = [ + "make_block", "DataManager", "ArrayManager", "BlockManager", @@ -54,7 +52,6 @@ def test_namespace(): "Block", "ExtensionBlock", "DatetimeTZBlock", - "make_block", ], ) def test_deprecations(name): @@ -63,9 +60,8 @@ def test_deprecations(name): with tm.assert_produces_warning(DeprecationWarning, match=msg): getattr(internals, name) - if name not in ["make_block", "NumericBlock", "ObjectBlock"]: - # NumericBlock and ObjectBlock are not in the internals.api namespace; - # make_block is not deprecated there. + if name not in ["NumericBlock", "ObjectBlock"]: + # NumericBlock and ObjectBlock are not in the internals.api namespace with tm.assert_produces_warning(DeprecationWarning, match=msg): getattr(api, name) diff --git a/pandas/tests/internals/test_internals.py b/pandas/tests/internals/test_internals.py index e228559a5f25d..597bc2975268e 100644 --- a/pandas/tests/internals/test_internals.py +++ b/pandas/tests/internals/test_internals.py @@ -4,7 +4,6 @@ ) import itertools import re -import warnings import numpy as np import pytest @@ -37,6 +36,7 @@ from pandas.core.internals import ( BlockManager, SingleBlockManager, + make_block, ) from pandas.core.internals.blocks import ( ensure_block_shape, @@ -44,11 +44,6 @@ new_block, ) -with warnings.catch_warnings(): - warnings.simplefilter("ignore") - from pandas.core.internals import make_block - - # this file contains BlockManager specific tests # TODO(ArrayManager) factor out interleave_dtype tests pytestmark = td.skip_array_manager_invalid_test From 1328057870880686097333e69b6bace5f140b65f Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 19 Sep 2023 07:33:06 -0700 Subject: [PATCH 5/7] pylint fixup --- pandas/core/internals/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/core/internals/__init__.py b/pandas/core/internals/__init__.py index 4aef605c31bf8..19ded07a6a34d 100644 --- a/pandas/core/internals/__init__.py +++ b/pandas/core/internals/__init__.py @@ -15,9 +15,9 @@ ) __all__ = [ - "Block", - "DatetimeTZBlock", - "ExtensionBlock", + "Block", # pylint: disable=undefined-all-variable + "DatetimeTZBlock", # pylint: disable=undefined-all-variable + "ExtensionBlock", # pylint: disable=undefined-all-variable "make_block", "DataManager", "ArrayManager", From 4f9fa6585fbf83a33e27bd67cdb3268b70cc009b Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 17 Oct 2023 15:25:53 -0700 Subject: [PATCH 6/7] doc fixup --- doc/source/whatsnew/v2.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index f5e6630db633f..9bdeacaedb8e0 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -232,8 +232,8 @@ For example: pd.date_range('2020-01-01', periods=3, freq='ME') Other Deprecations -- Changed :meth:`Timedelta.resolution_string` to return ``h``, ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``H``, ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`) ^^^^^^^^^^^^^^^^^^ +- Changed :meth:`Timedelta.resolution_string` to return ``h``, ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``H``, ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`) - Deprecated :meth:`Index.format`, use ``index.astype(str)`` or ``index.map(formatter)`` instead (:issue:`55413`) - Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, and ``DatetimeTZBlock``, use public APIs instead (:issue:`55139`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_clipboard`. (:issue:`54229`) From 5e506ed39ed3f0b328bf5bddc263b3d2248e597f Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 13 Nov 2023 17:13:23 -0800 Subject: [PATCH 7/7] hard-code stacklevel=2 --- pandas/core/internals/__init__.py | 10 ++++++---- pandas/core/internals/api.py | 6 +++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pandas/core/internals/__init__.py b/pandas/core/internals/__init__.py index 3372ed09c6eef..2eb413440ba9c 100644 --- a/pandas/core/internals/__init__.py +++ b/pandas/core/internals/__init__.py @@ -32,15 +32,15 @@ def __getattr__(name: str): # GH#55139 import warnings - from pandas.util._exceptions import find_stack_level - if name == "create_block_manager_from_blocks": # GH#33892 warnings.warn( f"{name} is deprecated and will be removed in a future version. " "Use public APIs instead.", DeprecationWarning, - stacklevel=find_stack_level(), + # https://github.com/pandas-dev/pandas/pull/55139#pullrequestreview-1720690758 + # on hard-coding stacklevel + stacklevel=2, ) from pandas.core.internals.managers import create_block_manager_from_blocks @@ -57,7 +57,9 @@ def __getattr__(name: str): f"{name} is deprecated and will be removed in a future version. " "Use public APIs instead.", DeprecationWarning, - stacklevel=find_stack_level(), + # https://github.com/pandas-dev/pandas/pull/55139#pullrequestreview-1720690758 + # on hard-coding stacklevel + stacklevel=2, ) if name == "NumericBlock": from pandas.core.internals.blocks import NumericBlock diff --git a/pandas/core/internals/api.py b/pandas/core/internals/api.py index 7ffa49f381350..b0b3937ca47ea 100644 --- a/pandas/core/internals/api.py +++ b/pandas/core/internals/api.py @@ -115,8 +115,6 @@ def __getattr__(name: str): # GH#55139 import warnings - from pandas.util._exceptions import find_stack_level - if name in [ "Block", "ExtensionBlock", @@ -128,7 +126,9 @@ def __getattr__(name: str): f"{name} is deprecated and will be removed in a future version. " "Use public APIs instead.", DeprecationWarning, - stacklevel=find_stack_level(), + # https://github.com/pandas-dev/pandas/pull/55139#pullrequestreview-1720690758 + # on hard-coding stacklevel + stacklevel=2, ) if name == "create_block_manager_from_blocks":