Skip to content

Commit

Permalink
CLN/DEPR: remove Block._holder, deprecated Block.is_categorical (pand…
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored and vladu committed Apr 5, 2021
1 parent efeb304 commit 869a5aa
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 47 deletions.
43 changes: 17 additions & 26 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
Union,
cast,
)
import warnings

import numpy as np

Expand Down Expand Up @@ -192,16 +193,6 @@ def __init__(self, values, placement: BlockPlacement, ndim: int):
self._mgr_locs = placement
self.values = values

@property
def _holder(self):
"""
The array-like that can hold the underlying values.
None for 'Block', overridden by subclasses that don't
use an ndarray.
"""
return None

@final
@property
def _consolidate_key(self):
Expand All @@ -228,7 +219,14 @@ def _can_hold_na(self) -> bool:
@final
@property
def is_categorical(self) -> bool:
return self._holder is Categorical
warnings.warn(
"Block.is_categorical is deprecated and will be removed in a "
"future version. Use isinstance(block.values, Categorical) "
"instead. See https://github.com/pandas-dev/pandas/issues/40226",
DeprecationWarning,
stacklevel=2,
)
return isinstance(self.values, Categorical)

@final
def external_values(self):
Expand Down Expand Up @@ -798,8 +796,10 @@ def _replace_list(
"""
See BlockManager._replace_list docstring.
"""
values = self.values

# TODO: dont special-case Categorical
if self.is_categorical and len(algos.unique(dest_list)) == 1:
if isinstance(values, Categorical) and len(algos.unique(dest_list)) == 1:
# We likely got here by tiling value inside NDFrame.replace,
# so un-tile here
return self.replace(src_list, dest_list[0], inplace, regex)
Expand All @@ -814,17 +814,17 @@ def _replace_list(

src_len = len(pairs) - 1

if self.is_object:
if values.dtype == _dtype_obj:
# Calculate the mask once, prior to the call of comp
# in order to avoid repeating the same computations
mask = ~isna(self.values)
mask = ~isna(values)
masks = [
compare_or_regex_search(self.values, s[0], regex=regex, mask=mask)
compare_or_regex_search(values, s[0], regex=regex, mask=mask)
for s in pairs
]
else:
# GH#38086 faster if we know we dont need to check for regex
masks = [missing.mask_missing(self.values, s[0]) for s in pairs]
masks = [missing.mask_missing(values, s[0]) for s in pairs]

# error: Argument 1 to "extract_bool_array" has incompatible type
# "Union[ExtensionArray, ndarray, bool]"; expected "Union[ExtensionArray,
Expand Down Expand Up @@ -1503,11 +1503,6 @@ def putmask(self, mask, new) -> List[Block]:
new_values[mask] = new
return [self.make_block(values=new_values)]

@property
def _holder(self):
# For extension blocks, the holder is values-dependent.
return type(self.values)

@property
def is_view(self) -> bool:
"""Extension arrays are never treated as views."""
Expand Down Expand Up @@ -1713,7 +1708,7 @@ def where(self, other, cond, errors="raise") -> List[Block]:
# NotImplementedError for class not implementing `__setitem__`
# TypeError for SparseArray, which implements just to raise
# a TypeError
result = self._holder._from_sequence(
result = type(self.values)._from_sequence(
np.where(cond, self.values, other), dtype=dtype
)

Expand Down Expand Up @@ -1903,10 +1898,6 @@ class DatetimeLikeBlockMixin(NDArrayBackedExtensionBlock):
def array_values(self):
return ensure_wrapped_if_datetimelike(self.values)

@property
def _holder(self):
return type(self.array_values())


class DatetimeBlock(DatetimeLikeBlockMixin):
__slots__ = ()
Expand Down
3 changes: 2 additions & 1 deletion pandas/core/internals/concat.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import pandas.core.algorithms as algos
from pandas.core.arrays import (
Categorical,
DatetimeArray,
ExtensionArray,
)
Expand Down Expand Up @@ -367,7 +368,7 @@ def get_reindexed_values(self, empty_dtype: DtypeObj, upcasted_na) -> ArrayLike:
# preserve these for validation in concat_compat
return self.block.values

if self.block.is_bool and not self.block.is_categorical:
if self.block.is_bool and not isinstance(self.block.values, Categorical):
# External code requested filling/upcasting, bool values must
# be upcasted to object to avoid being upcasted to numeric.
values = self.block.astype(np.object_).values
Expand Down
27 changes: 7 additions & 20 deletions pandas/tests/internals/test_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@
)
import pandas._testing as tm
import pandas.core.algorithms as algos
from pandas.core.arrays import (
DatetimeArray,
SparseArray,
TimedeltaArray,
)
from pandas.core.arrays import SparseArray
from pandas.core.internals import (
BlockManager,
SingleBlockManager,
Expand Down Expand Up @@ -320,6 +316,12 @@ def test_split(self):
for res, exp in zip(result, expected):
assert_block_equal(res, exp)

def test_is_categorical_deprecated(self):
# GH#40571
blk = self.fblock
with tm.assert_produces_warning(DeprecationWarning):
blk.is_categorical


class TestBlockManager:
def test_attrs(self):
Expand Down Expand Up @@ -1302,21 +1304,6 @@ def test_should_store_categorical(self):
assert not blk.should_store(np.asarray(cat))


@pytest.mark.parametrize(
"typestr, holder",
[
("category", Categorical),
("M8[ns]", DatetimeArray),
("M8[ns, US/Central]", DatetimeArray),
("m8[ns]", TimedeltaArray),
("sparse", SparseArray),
],
)
def test_holder(typestr, holder, block_maker):
blk = create_block(typestr, [1], maker=block_maker)
assert blk._holder is holder


def test_validate_ndim(block_maker):
values = np.array([1.0, 2.0])
placement = slice(2)
Expand Down

0 comments on commit 869a5aa

Please sign in to comment.