Skip to content

Commit 8747be1

Browse files
TomAugspurgerjreback
authored andcommitted
Remove _DtypeOpsMixin (#26331)
* Remove _DtypeOpsMixin * cleanup dead code
1 parent 5049c7f commit 8747be1

File tree

6 files changed

+138
-154
lines changed

6 files changed

+138
-154
lines changed

pandas/core/dtypes/base.py

+122-135
Original file line numberDiff line numberDiff line change
@@ -8,141 +8,7 @@
88
from pandas.core.dtypes.generic import ABCDataFrame, ABCIndexClass, ABCSeries
99

1010

11-
class _DtypeOpsMixin:
12-
# Not all of pandas' extension dtypes are compatibile with
13-
# the new ExtensionArray interface. This means PandasExtensionDtype
14-
# can't subclass ExtensionDtype yet, as is_extension_array_dtype would
15-
# incorrectly say that these types are extension types.
16-
#
17-
# In the interim, we put methods that are shared between the two base
18-
# classes ExtensionDtype and PandasExtensionDtype here. Both those base
19-
# classes will inherit from this Mixin. Once everything is compatible, this
20-
# class's methods can be moved to ExtensionDtype and removed.
21-
22-
# na_value is the default NA value to use for this type. This is used in
23-
# e.g. ExtensionArray.take. This should be the user-facing "boxed" version
24-
# of the NA value, not the physical NA vaalue for storage.
25-
# e.g. for JSONArray, this is an empty dictionary.
26-
na_value = np.nan
27-
_metadata = () # type: Tuple[str, ...]
28-
29-
def __eq__(self, other):
30-
"""Check whether 'other' is equal to self.
31-
32-
By default, 'other' is considered equal if either
33-
34-
* it's a string matching 'self.name'.
35-
* it's an instance of this type and all of the
36-
the attributes in ``self._metadata`` are equal between
37-
`self` and `other`.
38-
39-
Parameters
40-
----------
41-
other : Any
42-
43-
Returns
44-
-------
45-
bool
46-
"""
47-
if isinstance(other, str):
48-
try:
49-
other = self.construct_from_string(other)
50-
except TypeError:
51-
return False
52-
if isinstance(other, type(self)):
53-
return all(
54-
getattr(self, attr) == getattr(other, attr)
55-
for attr in self._metadata
56-
)
57-
return False
58-
59-
def __hash__(self):
60-
return hash(tuple(getattr(self, attr) for attr in self._metadata))
61-
62-
def __ne__(self, other):
63-
return not self.__eq__(other)
64-
65-
@property
66-
def names(self) -> Optional[List[str]]:
67-
"""Ordered list of field names, or None if there are no fields.
68-
69-
This is for compatibility with NumPy arrays, and may be removed in the
70-
future.
71-
"""
72-
return None
73-
74-
@classmethod
75-
def is_dtype(cls, dtype):
76-
"""Check if we match 'dtype'.
77-
78-
Parameters
79-
----------
80-
dtype : object
81-
The object to check.
82-
83-
Returns
84-
-------
85-
is_dtype : bool
86-
87-
Notes
88-
-----
89-
The default implementation is True if
90-
91-
1. ``cls.construct_from_string(dtype)`` is an instance
92-
of ``cls``.
93-
2. ``dtype`` is an object and is an instance of ``cls``
94-
3. ``dtype`` has a ``dtype`` attribute, and any of the above
95-
conditions is true for ``dtype.dtype``.
96-
"""
97-
dtype = getattr(dtype, 'dtype', dtype)
98-
99-
if isinstance(dtype, (ABCSeries, ABCIndexClass,
100-
ABCDataFrame, np.dtype)):
101-
# https://github.com/pandas-dev/pandas/issues/22960
102-
# avoid passing data to `construct_from_string`. This could
103-
# cause a FutureWarning from numpy about failing elementwise
104-
# comparison from, e.g., comparing DataFrame == 'category'.
105-
return False
106-
elif dtype is None:
107-
return False
108-
elif isinstance(dtype, cls):
109-
return True
110-
try:
111-
return cls.construct_from_string(dtype) is not None
112-
except TypeError:
113-
return False
114-
115-
@property
116-
def _is_numeric(self) -> bool:
117-
"""
118-
Whether columns with this dtype should be considered numeric.
119-
120-
By default ExtensionDtypes are assumed to be non-numeric.
121-
They'll be excluded from operations that exclude non-numeric
122-
columns, like (groupby) reductions, plotting, etc.
123-
"""
124-
return False
125-
126-
@property
127-
def _is_boolean(self) -> bool:
128-
"""
129-
Whether this dtype should be considered boolean.
130-
131-
By default, ExtensionDtypes are assumed to be non-numeric.
132-
Setting this to True will affect the behavior of several places,
133-
e.g.
134-
135-
* is_bool
136-
* boolean indexing
137-
138-
Returns
139-
-------
140-
bool
141-
"""
142-
return False
143-
144-
145-
class ExtensionDtype(_DtypeOpsMixin):
11+
class ExtensionDtype:
14612
"""
14713
A custom data type, to be paired with an ExtensionArray.
14814
@@ -202,10 +68,52 @@ class property**.
20268
``pandas.errors.AbstractMethodError`` and no ``register`` method is
20369
provided for registering virtual subclasses.
20470
"""
71+
# na_value is the default NA value to use for this type. This is used in
72+
# e.g. ExtensionArray.take. This should be the user-facing "boxed" version
73+
# of the NA value, not the physical NA value for storage.
74+
# e.g. for JSONArray, this is an empty dictionary.
75+
na_value = np.nan
76+
_metadata = () # type: Tuple[str, ...]
20577

20678
def __str__(self):
20779
return self.name
20880

81+
def __eq__(self, other):
82+
"""Check whether 'other' is equal to self.
83+
84+
By default, 'other' is considered equal if either
85+
86+
* it's a string matching 'self.name'.
87+
* it's an instance of this type and all of the
88+
the attributes in ``self._metadata`` are equal between
89+
`self` and `other`.
90+
91+
Parameters
92+
----------
93+
other : Any
94+
95+
Returns
96+
-------
97+
bool
98+
"""
99+
if isinstance(other, str):
100+
try:
101+
other = self.construct_from_string(other)
102+
except TypeError:
103+
return False
104+
if isinstance(other, type(self)):
105+
return all(
106+
getattr(self, attr) == getattr(other, attr)
107+
for attr in self._metadata
108+
)
109+
return False
110+
111+
def __hash__(self):
112+
return hash(tuple(getattr(self, attr) for attr in self._metadata))
113+
114+
def __ne__(self, other):
115+
return not self.__eq__(other)
116+
209117
@property
210118
def type(self) -> Type:
211119
"""
@@ -243,6 +151,15 @@ def name(self) -> str:
243151
"""
244152
raise AbstractMethodError(self)
245153

154+
@property
155+
def names(self) -> Optional[List[str]]:
156+
"""Ordered list of field names, or None if there are no fields.
157+
158+
This is for compatibility with NumPy arrays, and may be removed in the
159+
future.
160+
"""
161+
return None
162+
246163
@classmethod
247164
def construct_array_type(cls):
248165
"""
@@ -286,3 +203,73 @@ def construct_from_string(cls, string):
286203
... "'{}'".format(cls, string))
287204
"""
288205
raise AbstractMethodError(cls)
206+
207+
@classmethod
208+
def is_dtype(cls, dtype):
209+
"""Check if we match 'dtype'.
210+
211+
Parameters
212+
----------
213+
dtype : object
214+
The object to check.
215+
216+
Returns
217+
-------
218+
is_dtype : bool
219+
220+
Notes
221+
-----
222+
The default implementation is True if
223+
224+
1. ``cls.construct_from_string(dtype)`` is an instance
225+
of ``cls``.
226+
2. ``dtype`` is an object and is an instance of ``cls``
227+
3. ``dtype`` has a ``dtype`` attribute, and any of the above
228+
conditions is true for ``dtype.dtype``.
229+
"""
230+
dtype = getattr(dtype, 'dtype', dtype)
231+
232+
if isinstance(dtype, (ABCSeries, ABCIndexClass,
233+
ABCDataFrame, np.dtype)):
234+
# https://github.com/pandas-dev/pandas/issues/22960
235+
# avoid passing data to `construct_from_string`. This could
236+
# cause a FutureWarning from numpy about failing elementwise
237+
# comparison from, e.g., comparing DataFrame == 'category'.
238+
return False
239+
elif dtype is None:
240+
return False
241+
elif isinstance(dtype, cls):
242+
return True
243+
try:
244+
return cls.construct_from_string(dtype) is not None
245+
except TypeError:
246+
return False
247+
248+
@property
249+
def _is_numeric(self) -> bool:
250+
"""
251+
Whether columns with this dtype should be considered numeric.
252+
253+
By default ExtensionDtypes are assumed to be non-numeric.
254+
They'll be excluded from operations that exclude non-numeric
255+
columns, like (groupby) reductions, plotting, etc.
256+
"""
257+
return False
258+
259+
@property
260+
def _is_boolean(self) -> bool:
261+
"""
262+
Whether this dtype should be considered boolean.
263+
264+
By default, ExtensionDtypes are assumed to be non-numeric.
265+
Setting this to True will affect the behavior of several places,
266+
e.g.
267+
268+
* is_bool
269+
* boolean indexing
270+
271+
Returns
272+
-------
273+
bool
274+
"""
275+
return False

pandas/core/dtypes/cast.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
is_integer, is_integer_dtype, is_object_dtype, is_scalar, is_string_dtype,
1919
is_timedelta64_dtype, is_timedelta64_ns_dtype, is_unsigned_integer_dtype,
2020
pandas_dtype)
21-
from .dtypes import (
22-
DatetimeTZDtype, ExtensionDtype, PandasExtensionDtype, PeriodDtype)
21+
from .dtypes import DatetimeTZDtype, ExtensionDtype, PeriodDtype
2322
from .generic import (
2423
ABCDatetimeArray, ABCDatetimeIndex, ABCPeriodArray, ABCPeriodIndex,
2524
ABCSeries)
@@ -1108,8 +1107,7 @@ def find_common_type(types):
11081107
if all(is_dtype_equal(first, t) for t in types[1:]):
11091108
return first
11101109

1111-
if any(isinstance(t, (PandasExtensionDtype, ExtensionDtype))
1112-
for t in types):
1110+
if any(isinstance(t, ExtensionDtype) for t in types):
11131111
return np.object
11141112

11151113
# take lowest unit

pandas/core/dtypes/common.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from pandas.core.dtypes.dtypes import (
1111
CategoricalDtype, DatetimeTZDtype, ExtensionDtype, IntervalDtype,
12-
PandasExtensionDtype, PeriodDtype, registry)
12+
PeriodDtype, registry)
1313
from pandas.core.dtypes.generic import (
1414
ABCCategorical, ABCDateOffset, ABCDatetimeIndex, ABCIndexClass,
1515
ABCPeriodArray, ABCPeriodIndex, ABCSeries)
@@ -1888,7 +1888,7 @@ def _is_dtype_type(arr_or_dtype, condition):
18881888
if isinstance(arr_or_dtype, np.dtype):
18891889
return condition(arr_or_dtype.type)
18901890
elif isinstance(arr_or_dtype, type):
1891-
if issubclass(arr_or_dtype, (PandasExtensionDtype, ExtensionDtype)):
1891+
if issubclass(arr_or_dtype, ExtensionDtype):
18921892
arr_or_dtype = arr_or_dtype.type
18931893
return condition(np.dtype(arr_or_dtype).type)
18941894
elif arr_or_dtype is None:
@@ -1936,7 +1936,7 @@ def infer_dtype_from_object(dtype):
19361936
if isinstance(dtype, type) and issubclass(dtype, np.generic):
19371937
# Type object from a dtype
19381938
return dtype
1939-
elif isinstance(dtype, (np.dtype, PandasExtensionDtype, ExtensionDtype)):
1939+
elif isinstance(dtype, (np.dtype, ExtensionDtype)):
19401940
# dtype object
19411941
try:
19421942
_validate_date_like_dtype(dtype)
@@ -2021,7 +2021,7 @@ def pandas_dtype(dtype):
20212021
# short-circuit
20222022
if isinstance(dtype, np.ndarray):
20232023
return dtype.dtype
2024-
elif isinstance(dtype, (np.dtype, PandasExtensionDtype, ExtensionDtype)):
2024+
elif isinstance(dtype, (np.dtype, ExtensionDtype)):
20252025
return dtype
20262026

20272027
# registered extension types

pandas/core/dtypes/dtypes.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from pandas.core.dtypes.generic import (
1313
ABCCategoricalIndex, ABCDateOffset, ABCIndexClass)
1414

15-
from .base import ExtensionDtype, _DtypeOpsMixin
15+
from .base import ExtensionDtype
1616
from .inference import is_list_like
1717

1818
str_type = str
@@ -68,7 +68,7 @@ def register(self, dtype):
6868
----------
6969
dtype : ExtensionDtype
7070
"""
71-
if not issubclass(dtype, (PandasExtensionDtype, ExtensionDtype)):
71+
if not issubclass(dtype, ExtensionDtype):
7272
raise ValueError("can only register pandas extension dtypes")
7373

7474
self.dtypes.append(dtype)
@@ -104,7 +104,7 @@ def find(self, dtype):
104104
registry = Registry()
105105

106106

107-
class PandasExtensionDtype(_DtypeOpsMixin):
107+
class PandasExtensionDtype(ExtensionDtype):
108108
"""
109109
A np.dtype duck-typed class, suitable for holding a custom dtype.
110110
@@ -577,7 +577,7 @@ def _is_boolean(self):
577577

578578

579579
@register_extension_dtype
580-
class DatetimeTZDtype(PandasExtensionDtype, ExtensionDtype):
580+
class DatetimeTZDtype(PandasExtensionDtype):
581581
"""
582582
An ExtensionDtype for timezone-aware datetime data.
583583
@@ -737,7 +737,7 @@ def __setstate__(self, state):
737737

738738

739739
@register_extension_dtype
740-
class PeriodDtype(ExtensionDtype, PandasExtensionDtype):
740+
class PeriodDtype(PandasExtensionDtype):
741741
"""
742742
An ExtensionDtype for Period data.
743743
@@ -894,7 +894,7 @@ def construct_array_type(cls):
894894

895895

896896
@register_extension_dtype
897-
class IntervalDtype(PandasExtensionDtype, ExtensionDtype):
897+
class IntervalDtype(PandasExtensionDtype):
898898
"""
899899
An ExtensionDtype for Interval data.
900900

0 commit comments

Comments
 (0)