Skip to content

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

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 8, 2021
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ Other API changes
- Accessing ``_constructor_expanddim`` on a :class:`DataFrame` and ``_constructor_sliced`` on a :class:`Series` now raise an ``AttributeError``. Previously a ``NotImplementedError`` was raised (:issue:`38782`)
- Added new ``engine`` and ``**engine_kwargs`` parameters to :meth:`DataFrame.to_sql` to support other future "SQL engines". Currently we still only use ``SQLAlchemy`` under the hood, but more engines are planned to be supported such as ``turbodbc`` (:issue:`36893`)
- Removed redundant ``freq`` from :class:`PeriodIndex` string representation (:issue:`41653`)
- :attr:`ExtensionArray._can_hold_na` should now be implemented on the :class:`ExtensionDtype` subclass as ``_can_hold_na`` (:issue:`40574`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove this mention, if we are not yet clear on the intended semantics of it.


Build
=====
Expand Down
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