From ff5d593de8750b7bf81bdf8af810cbded6e24c7e Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 21 Dec 2021 16:05:46 -0800 Subject: [PATCH 1/3] ENH: implement EADtype.empty --- pandas/core/dtypes/base.py | 14 ++++++++++++++ pandas/tests/extension/base/constructors.py | 8 +++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/pandas/core/dtypes/base.py b/pandas/core/dtypes/base.py index 372abee701b02..afd0d69e7e829 100644 --- a/pandas/core/dtypes/base.py +++ b/pandas/core/dtypes/base.py @@ -17,6 +17,7 @@ from pandas._libs.hashtable import object_hash from pandas._typing import ( DtypeObj, + Shape, npt, type_t, ) @@ -208,6 +209,19 @@ def construct_array_type(cls) -> type_t[ExtensionArray]: """ raise AbstractMethodError(cls) + def empty(self, shape: Shape) -> type_t[ExtensionArray]: + """ + Construct an ExtensionArray of this dtype with the given shape. + + Analogous to numpy.empty. + + Returns + ------- + ExtensionArray + """ + cls = self.construct_array_type() + return cls._empty(shape, dtype=self) + @classmethod def construct_from_string( cls: type_t[ExtensionDtypeT], string: str diff --git a/pandas/tests/extension/base/constructors.py b/pandas/tests/extension/base/constructors.py index 4ba315eeaeb15..c86054aed7e4d 100644 --- a/pandas/tests/extension/base/constructors.py +++ b/pandas/tests/extension/base/constructors.py @@ -126,6 +126,12 @@ def test_construct_empty_dataframe(self, dtype): def test_empty(self, dtype): cls = dtype.construct_array_type() result = cls._empty((4,), dtype=dtype) - assert isinstance(result, cls) assert result.dtype == dtype + assert result.shape == (4,) + + # GH#19600 method on ExtensionDtype + result2 = dtype.empty((4,)) + assert isinstance(result2, cls) + assert result2.dtype == dtype + assert result2.shape == (4,) From 78b0e71fe63bc45b43ba7885ca0cdcce69f1e3b9 Mon Sep 17 00:00:00 2001 From: Brock Date: Wed, 22 Dec 2021 18:46:31 -0800 Subject: [PATCH 2/3] ENH: implement EA._hasnans --- pandas/core/arrays/base.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pandas/core/arrays/base.py b/pandas/core/arrays/base.py index 8bcdd42b9f795..274be2a6a434b 100644 --- a/pandas/core/arrays/base.py +++ b/pandas/core/arrays/base.py @@ -425,7 +425,7 @@ def __contains__(self, item: object) -> bool | np.bool_: if not self._can_hold_na: return False elif item is self.dtype.na_value or isinstance(item, self.dtype.type): - return self.isna().any() + return self._hasnans else: return False else: @@ -603,6 +603,16 @@ def isna(self) -> np.ndarray | ExtensionArraySupportsAnyAll: """ raise AbstractMethodError(self) + @property + def _hasnans(self) -> bool: + # GH#22680 + """ + Equivalent to `self.isna().any()`. + + Some ExtensionArray subclasses may be able to optimize this check. + """ + return self.isna().any() + def _values_for_argsort(self) -> np.ndarray: """ Return values for sorting. @@ -686,7 +696,7 @@ def argmin(self, skipna: bool = True) -> int: ExtensionArray.argmax """ validate_bool_kwarg(skipna, "skipna") - if not skipna and self.isna().any(): + if not skipna and self._hasnans: raise NotImplementedError return nargminmax(self, "argmin") @@ -710,7 +720,7 @@ def argmax(self, skipna: bool = True) -> int: ExtensionArray.argmin """ validate_bool_kwarg(skipna, "skipna") - if not skipna and self.isna().any(): + if not skipna and self._hasnans: raise NotImplementedError return nargminmax(self, "argmax") From 14a103a1863241165b93ee25c4272e390fdfedb9 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 23 Dec 2021 08:17:07 -0800 Subject: [PATCH 3/3] mypy fixup --- pandas/core/arrays/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/arrays/base.py b/pandas/core/arrays/base.py index 274be2a6a434b..fc915f5f84d8b 100644 --- a/pandas/core/arrays/base.py +++ b/pandas/core/arrays/base.py @@ -611,7 +611,7 @@ def _hasnans(self) -> bool: Some ExtensionArray subclasses may be able to optimize this check. """ - return self.isna().any() + return bool(self.isna().any()) def _values_for_argsort(self) -> np.ndarray: """