Skip to content

API: EA._can_hold_na -> EDtype.can_hold_na #41654

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 11 commits into from
Jun 8, 2021
5 changes: 4 additions & 1 deletion pandas/core/arrays/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from pandas.util._decorators import (
Appender,
Substitution,
cache_readonly,
)
from pandas.util._validators import (
validate_bool_kwarg,
Expand Down Expand Up @@ -1273,7 +1274,9 @@ def _concat_same_type(
# such as take(), reindex(), shift(), etc. In addition, those results
# will then be of the ExtensionArray subclass rather than an array
# of objects
_can_hold_na = True
@cache_readonly
def _can_hold_na(self) -> bool:
return self.dtype._can_hold_na

def _reduce(self, name: str, *, skipna: bool = True, **kwargs):
"""
Expand Down
1 change: 0 additions & 1 deletion pandas/core/arrays/categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ class Categorical(NDArrayBackedExtensionArray, PandasObject, ObjectStringArrayMi
# tolist is not actually deprecated, just suppressed in the __dir__
_hidden_attrs = PandasObject._hidden_attrs | frozenset(["tolist"])
_typ = "categorical"
_can_hold_na = True

_dtype: CategoricalDtype

Expand Down
4 changes: 4 additions & 0 deletions pandas/core/arrays/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ class DatetimeLikeArrayMixin(OpsMixin, NDArrayBackedExtensionArray):
_recognized_scalars: tuple[type, ...]
_ndarray: np.ndarray

@cache_readonly
def _can_hold_na(self) -> bool:
return True

def __init__(self, data, dtype: Dtype | None = None, freq=None, copy=False):
raise AbstractMethodError(self)

Expand Down
7 changes: 7 additions & 0 deletions pandas/core/dtypes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,13 @@ def _get_common_dtype(self, dtypes: list[DtypeObj]) -> DtypeObj | None:
else:
return None

@property
def _can_hold_na(self) -> bool:
"""
Can arrays of this dtype hold NA values?
"""
return True


def register_extension_dtype(cls: type[E]) -> type[E]:
"""
Expand Down
10 changes: 5 additions & 5 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,15 @@ def is_view(self) -> bool:
return values.base is not None

@final
@property
@cache_readonly
def _can_hold_na(self) -> bool:
"""
Can we store NA values in this Block?
"""
values = self.values
if isinstance(values, np.ndarray):
return values.dtype.kind not in ["b", "i", "u"]
return values._can_hold_na
dtype = self.dtype
if isinstance(dtype, np.dtype):
return dtype.kind not in ["b", "i", "u"]
return dtype._can_hold_na

@final
@cache_readonly
Expand Down
8 changes: 5 additions & 3 deletions pandas/tests/extension/test_external_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
class CustomBlock(ExtensionBlock):

_holder = np.ndarray
# error: Cannot override final attribute "_can_hold_na"
# (previously declared in base class "Block")
_can_hold_na = False # type: ignore[misc]

# Cannot override final attribute "_can_hold_na"
@property # type: ignore[misc]
def _can_hold_na(self) -> bool:
return False


@pytest.fixture
Expand Down