diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index ec5027840dfd5..dbcb88a99cf3b 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -418,6 +418,7 @@ Other API changes an empty ``RangeIndex`` or empty ``Index`` with object dtype when determining the dtype of the resulting Index (:issue:`60797`) - :class:`IncompatibleFrequency` now subclasses ``TypeError`` instead of ``ValueError``. As a result, joins with mismatched frequencies now cast to object like other non-comparable joins, and arithmetic with indexes with mismatched frequencies align (:issue:`55782`) +- :meth:`ExtensionDtype.construct_array_type` is now a regular method instead of a ``classmethod`` (:issue:`58663`) - Comparison operations between :class:`Index` and :class:`Series` now consistently return :class:`Series` regardless of which object is on the left or right (:issue:`36759`) - Numpy functions like ``np.isinf`` that return a bool dtype when called on a :class:`Index` object now return a bool-dtype :class:`Index` instead of ``np.ndarray`` (:issue:`52676`) diff --git a/pandas/core/arrays/boolean.py b/pandas/core/arrays/boolean.py index 87c18fe346c62..dc236d82543cc 100644 --- a/pandas/core/arrays/boolean.py +++ b/pandas/core/arrays/boolean.py @@ -85,8 +85,7 @@ def kind(self) -> str: def numpy_dtype(self) -> np.dtype: return np.dtype("bool") - @classmethod - def construct_array_type(cls) -> type_t[BooleanArray]: + def construct_array_type(self) -> type_t[BooleanArray]: """ Return the array type associated with this dtype. diff --git a/pandas/core/arrays/floating.py b/pandas/core/arrays/floating.py index 67c23f4825a7f..2db95b4baee75 100644 --- a/pandas/core/arrays/floating.py +++ b/pandas/core/arrays/floating.py @@ -28,8 +28,7 @@ class FloatingDtype(NumericDtype): _default_np_dtype = np.dtype(np.float64) _checker = is_float_dtype - @classmethod - def construct_array_type(cls) -> type[FloatingArray]: + def construct_array_type(self) -> type[FloatingArray]: """ Return the array type associated with this dtype. diff --git a/pandas/core/arrays/integer.py b/pandas/core/arrays/integer.py index afbadd754cdbc..b14044de287fa 100644 --- a/pandas/core/arrays/integer.py +++ b/pandas/core/arrays/integer.py @@ -28,8 +28,7 @@ class IntegerDtype(NumericDtype): _default_np_dtype = np.dtype(np.int64) _checker = is_integer_dtype - @classmethod - def construct_array_type(cls) -> type[IntegerArray]: + def construct_array_type(self) -> type[IntegerArray]: """ Return the array type associated with this dtype. diff --git a/pandas/core/arrays/numeric.py b/pandas/core/arrays/numeric.py index f319a3cc05575..59279d24231e0 100644 --- a/pandas/core/arrays/numeric.py +++ b/pandas/core/arrays/numeric.py @@ -150,7 +150,7 @@ def _coerce_to_data_and_mask( if dtype is not None: dtype = dtype_cls._standardize_dtype(dtype) - cls = dtype_cls.construct_array_type() + cls = dtype_cls().construct_array_type() if isinstance(values, cls): values, mask = values._data, values._mask if dtype is not None: diff --git a/pandas/core/arrays/string_.py b/pandas/core/arrays/string_.py index 198dc4c483277..c124c5ed3845b 100644 --- a/pandas/core/arrays/string_.py +++ b/pandas/core/arrays/string_.py @@ -283,12 +283,7 @@ def construct_from_string(cls, string) -> Self: else: raise TypeError(f"Cannot construct a '{cls.__name__}' from '{string}'") - # https://github.com/pandas-dev/pandas/issues/36126 - # error: Signature of "construct_array_type" incompatible with supertype - # "ExtensionDtype" - def construct_array_type( # type: ignore[override] - self, - ) -> type_t[BaseStringArray]: + def construct_array_type(self) -> type_t[BaseStringArray]: """ Return the array type associated with this dtype. diff --git a/pandas/core/dtypes/base.py b/pandas/core/dtypes/base.py index 428fc24cd08ac..b53fc84328eca 100644 --- a/pandas/core/dtypes/base.py +++ b/pandas/core/dtypes/base.py @@ -211,8 +211,7 @@ def names(self) -> list[str] | None: """ return None - @classmethod - def construct_array_type(cls) -> type_t[ExtensionArray]: + def construct_array_type(self) -> type_t[ExtensionArray]: """ Return the array type associated with this dtype. @@ -220,7 +219,7 @@ def construct_array_type(cls) -> type_t[ExtensionArray]: ------- type """ - raise AbstractMethodError(cls) + raise AbstractMethodError(self) def empty(self, shape: Shape) -> ExtensionArray: """ diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index 79976cfd51352..be71414b06207 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -527,8 +527,7 @@ def _hash_categories(self) -> int: combined_hashed = combine_hash_arrays(iter(cat_array), num_items=len(cat_array)) return np.bitwise_xor.reduce(combined_hashed) - @classmethod - def construct_array_type(cls) -> type_t[Categorical]: + def construct_array_type(self) -> type_t[Categorical]: """ Return the array type associated with this dtype. @@ -856,8 +855,7 @@ def tz(self) -> tzinfo: """ return self._tz - @classmethod - def construct_array_type(cls) -> type_t[DatetimeArray]: + def construct_array_type(self) -> type_t[DatetimeArray]: """ Return the array type associated with this dtype. @@ -1174,8 +1172,7 @@ def is_dtype(cls, dtype: object) -> bool: return False return super().is_dtype(dtype) - @classmethod - def construct_array_type(cls) -> type_t[PeriodArray]: + def construct_array_type(self) -> type_t[PeriodArray]: """ Return the array type associated with this dtype. @@ -1363,8 +1360,7 @@ def subtype(self): """ return self._subtype - @classmethod - def construct_array_type(cls) -> type[IntervalArray]: + def construct_array_type(self) -> type[IntervalArray]: """ Return the array type associated with this dtype. @@ -1576,8 +1572,7 @@ def construct_from_string(cls, string: str) -> NumpyEADtype: raise TypeError(msg) from err return cls(dtype) - @classmethod - def construct_array_type(cls) -> type_t[NumpyExtensionArray]: + def construct_array_type(self) -> type_t[NumpyExtensionArray]: """ Return the array type associated with this dtype. @@ -1649,8 +1644,7 @@ def itemsize(self) -> int: """Return the number of bytes in this dtype""" return self.numpy_dtype.itemsize - @classmethod - def construct_array_type(cls) -> type_t[BaseMaskedArray]: + def construct_array_type(self) -> type_t[BaseMaskedArray]: """ Return the array type associated with this dtype. @@ -1914,8 +1908,7 @@ def name(self) -> str: def __repr__(self) -> str: return self.name - @classmethod - def construct_array_type(cls) -> type_t[SparseArray]: + def construct_array_type(self) -> type_t[SparseArray]: """ Return the array type associated with this dtype. @@ -2316,8 +2309,7 @@ def itemsize(self) -> int: """Return the number of bytes in this dtype""" return self.numpy_dtype.itemsize - @classmethod - def construct_array_type(cls) -> type_t[ArrowExtensionArray]: + def construct_array_type(self) -> type_t[ArrowExtensionArray]: """ Return the array type associated with this dtype. diff --git a/pandas/tests/arrays/test_array.py b/pandas/tests/arrays/test_array.py index fa939a390a66f..cd78dfd6f343a 100644 --- a/pandas/tests/arrays/test_array.py +++ b/pandas/tests/arrays/test_array.py @@ -487,8 +487,7 @@ def test_bounds_check(): class DecimalDtype2(DecimalDtype): name = "decimal2" - @classmethod - def construct_array_type(cls): + def construct_array_type(self): """ Return the array type associated with this dtype. diff --git a/pandas/tests/dtypes/test_common.py b/pandas/tests/dtypes/test_common.py index d30fa9fc2ea0f..cd5050cab8ad5 100644 --- a/pandas/tests/dtypes/test_common.py +++ b/pandas/tests/dtypes/test_common.py @@ -576,8 +576,7 @@ def type(self): def name(self): raise NotImplementedError - @classmethod - def construct_array_type(cls): + def construct_array_type(self): raise NotImplementedError def _is_numeric(self) -> bool: diff --git a/pandas/tests/extension/array_with_attr/array.py b/pandas/tests/extension/array_with_attr/array.py index 4f65424ece145..e9cd16b102db4 100644 --- a/pandas/tests/extension/array_with_attr/array.py +++ b/pandas/tests/extension/array_with_attr/array.py @@ -24,8 +24,7 @@ class FloatAttrDtype(ExtensionDtype): name = "float_attr" na_value = np.nan - @classmethod - def construct_array_type(cls) -> type_t[FloatAttrArray]: + def construct_array_type(self) -> type_t[FloatAttrArray]: """ Return the array type associated with this dtype. diff --git a/pandas/tests/extension/date/array.py b/pandas/tests/extension/date/array.py index 0c51570189a7c..d99adba0ef8c0 100644 --- a/pandas/tests/extension/date/array.py +++ b/pandas/tests/extension/date/array.py @@ -48,8 +48,7 @@ def construct_from_string(cls, string: str): else: raise TypeError(f"Cannot construct a '{cls.__name__}' from '{string}'") - @classmethod - def construct_array_type(cls): + def construct_array_type(self): return DateArray @property diff --git a/pandas/tests/extension/decimal/array.py b/pandas/tests/extension/decimal/array.py index 2ee6a73ec4054..45991e32726c6 100644 --- a/pandas/tests/extension/decimal/array.py +++ b/pandas/tests/extension/decimal/array.py @@ -50,8 +50,7 @@ def __init__(self, context=None) -> None: def __repr__(self) -> str: return f"DecimalDtype(context={self.context})" - @classmethod - def construct_array_type(cls) -> type_t[DecimalArray]: + def construct_array_type(self) -> type_t[DecimalArray]: """ Return the array type associated with this dtype. diff --git a/pandas/tests/extension/decimal/test_decimal.py b/pandas/tests/extension/decimal/test_decimal.py index e0b35b7450303..5221cd402f53d 100644 --- a/pandas/tests/extension/decimal/test_decimal.py +++ b/pandas/tests/extension/decimal/test_decimal.py @@ -286,8 +286,7 @@ def test_combine_from_sequence_raises(monkeypatch): # https://github.com/pandas-dev/pandas/issues/22850 cls = DecimalArrayWithoutFromSequence - @classmethod - def construct_array_type(cls): + def construct_array_type(self): return DecimalArrayWithoutFromSequence monkeypatch.setattr(DecimalDtype, "construct_array_type", construct_array_type) diff --git a/pandas/tests/extension/json/array.py b/pandas/tests/extension/json/array.py index b110911bda400..a1799d0c113d1 100644 --- a/pandas/tests/extension/json/array.py +++ b/pandas/tests/extension/json/array.py @@ -54,8 +54,7 @@ class JSONDtype(ExtensionDtype): name = "json" na_value: Mapping[str, Any] = UserDict() - @classmethod - def construct_array_type(cls) -> type_t[JSONArray]: + def construct_array_type(self) -> type_t[JSONArray]: """ Return the array type associated with this dtype. diff --git a/pandas/tests/extension/list/array.py b/pandas/tests/extension/list/array.py index 8b4728c7d6292..009462a1406ec 100644 --- a/pandas/tests/extension/list/array.py +++ b/pandas/tests/extension/list/array.py @@ -30,8 +30,7 @@ class ListDtype(ExtensionDtype): name = "list" na_value = np.nan - @classmethod - def construct_array_type(cls) -> type_t[ListArray]: + def construct_array_type(self) -> type_t[ListArray]: """ Return the array type associated with this dtype. diff --git a/pandas/tests/frame/methods/test_astype.py b/pandas/tests/frame/methods/test_astype.py index c428bd1820cb1..59cc0eab2f62e 100644 --- a/pandas/tests/frame/methods/test_astype.py +++ b/pandas/tests/frame/methods/test_astype.py @@ -857,8 +857,7 @@ def copy(self): class Int16DtypeNoCopy(pd.Int16Dtype): # GH 42501 - @classmethod - def construct_array_type(cls): + def construct_array_type(self): return IntegerArrayNoCopy