Skip to content

Commit 38b56a0

Browse files
authored
DEPR: is_bool_dtype special-casing Index[object_all_bools] (#52680)
* DEPR: is_bool_dtype special-casing Index[object_all_bools] * GH ref * Move whatsnew
1 parent 832bb05 commit 38b56a0

File tree

6 files changed

+30
-13
lines changed

6 files changed

+30
-13
lines changed

doc/source/whatsnew/v2.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ Deprecations
238238
- Deprecated parameter ``convert_type`` in :meth:`Series.apply` (:issue:`52140`)
239239
- Deprecated passing a dictionary to :meth:`.SeriesGroupBy.agg`; pass a list of aggregations instead (:issue:`50684`)
240240
- Deprecated the "fastpath" keyword in :class:`Categorical` constructor, use :meth:`Categorical.from_codes` instead (:issue:`20110`)
241+
- Deprecated the behavior of :func:`is_bool_dtype` returning ``True`` for object-dtype :class:`Index` of bool objects (:issue:`52680`)
241242
- Deprecated the methods :meth:`Series.bool` and :meth:`DataFrame.bool` (:issue:`51749`)
242243
- Deprecated unused "closed" and "normalize" keywords in the :class:`DatetimeIndex` constructor (:issue:`52628`)
243244
- Deprecated unused "closed" keyword in the :class:`TimedeltaIndex` constructor (:issue:`52628`)

pandas/core/dtypes/common.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,18 @@ def is_bool_dtype(arr_or_dtype) -> bool:
12191219

12201220
if isinstance(arr_or_dtype, ABCIndex):
12211221
# Allow Index[object] that is all-bools or Index["boolean"]
1222-
return arr_or_dtype.inferred_type == "boolean"
1222+
if arr_or_dtype.inferred_type == "boolean":
1223+
if not is_bool_dtype(arr_or_dtype.dtype):
1224+
# GH#52680
1225+
warnings.warn(
1226+
"The behavior of is_bool_dtype with an object-dtype Index "
1227+
"of bool objects is deprecated. In a future version, "
1228+
"this will return False. Cast the Index to a bool dtype instead.",
1229+
FutureWarning,
1230+
stacklevel=find_stack_level(),
1231+
)
1232+
return True
1233+
return False
12231234
elif isinstance(dtype, ExtensionDtype):
12241235
return getattr(dtype, "_is_boolean", False)
12251236

pandas/core/indexes/base.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,13 @@ def __array_wrap__(self, result, context=None):
926926
Gets called after a ufunc and other functions e.g. np.split.
927927
"""
928928
result = lib.item_from_zerodim(result)
929-
if is_bool_dtype(result) or lib.is_scalar(result) or np.ndim(result) > 1:
929+
if (
930+
(not isinstance(result, Index) and is_bool_dtype(result))
931+
or lib.is_scalar(result)
932+
or np.ndim(result) > 1
933+
):
934+
# exclude Index to avoid warning from is_bool_dtype deprecation;
935+
# in the Index case it doesn't matter which path we go down.
930936
return result
931937

932938
return Index(result, name=self.name)
@@ -6107,8 +6113,12 @@ def _should_compare(self, other: Index) -> bool:
61076113
Check if `self == other` can ever have non-False entries.
61086114
"""
61096115

6110-
if (is_bool_dtype(other) and is_any_real_numeric_dtype(self)) or (
6111-
is_bool_dtype(self) and is_any_real_numeric_dtype(other)
6116+
# NB: we use inferred_type rather than is_bool_dtype to catch
6117+
# object_dtype_of_bool and categorical[object_dtype_of_bool] cases
6118+
if (
6119+
other.inferred_type == "boolean" and is_any_real_numeric_dtype(self.dtype)
6120+
) or (
6121+
self.inferred_type == "boolean" and is_any_real_numeric_dtype(other.dtype)
61126122
):
61136123
# GH#16877 Treat boolean labels passed to a numeric index as not
61146124
# found. Without this fix False and True would be treated as 0 and 1

pandas/tests/base/common.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
from typing import Any
22

33
from pandas import Index
4-
from pandas.api.types import is_bool_dtype
54

65

76
def allow_na_ops(obj: Any) -> bool:
87
"""Whether to skip test cases including NaN"""
9-
is_bool_index = isinstance(obj, Index) and is_bool_dtype(obj)
8+
is_bool_index = isinstance(obj, Index) and obj.inferred_type == "boolean"
109
return not is_bool_index and obj._can_hold_na

pandas/tests/indexes/test_setops.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
)
2222
import pandas._testing as tm
2323
from pandas.api.types import (
24-
is_bool_dtype,
2524
is_signed_integer_dtype,
2625
pandas_dtype,
2726
)
@@ -242,7 +241,7 @@ def test_union_base(self, index):
242241
def test_difference_base(self, sort, index):
243242
first = index[2:]
244243
second = index[:4]
245-
if is_bool_dtype(index):
244+
if index.inferred_type == "boolean":
246245
# i think (TODO: be sure) there assumptions baked in about
247246
# the index fixture that don't hold here?
248247
answer = set(first).difference(set(second))

pandas/tests/indexing/test_loc.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@
3737
to_timedelta,
3838
)
3939
import pandas._testing as tm
40-
from pandas.api.types import (
41-
is_bool_dtype,
42-
is_scalar,
43-
)
40+
from pandas.api.types import is_scalar
4441
from pandas.core.indexing import _one_ellipsis_message
4542
from pandas.tests.indexing.common import check_indexing_smoketest_or_raises
4643

@@ -1657,7 +1654,7 @@ def test_loc_iloc_getitem_leading_ellipses(self, series_with_simple_index, index
16571654
obj = series_with_simple_index
16581655
key = 0 if (indexer is tm.iloc or len(obj) == 0) else obj.index[0]
16591656

1660-
if indexer is tm.loc and is_bool_dtype(obj.index):
1657+
if indexer is tm.loc and obj.index.inferred_type == "boolean":
16611658
# passing [False] will get interpreted as a boolean mask
16621659
# TODO: should it? unambiguous when lengths dont match?
16631660
return

0 commit comments

Comments
 (0)